<commit_before>goog.provide('ol.layer.Base');
goog.provide('ol.layer.LayerProperty');
goog.provide('ol.layer.LayerState');

goog.require('goog.events');
goog.require('goog.math');
goog.require('goog.object');
goog.require('ol.Object');
goog.require('ol.source.State');

/**
 * @enum {string}
 */
ol.layer.LayerProperty = {
  BRIGHTNESS: 'brightness',
  CONTRAST: 'contrast',
  HUE: 'hue',
  OPACITY: 'opacity',
  SATURATION: 'saturation',
  VISIBLE: 'visible',
  EXTENT: 'extent',
  MAX_RESOLUTION: 'maxResolution',
  MIN_RESOLUTION: 'minResolution',
  SOURCE: 'source'
};

/**
 * @typedef {{layer: ol.layer.Layer,
 *            brightness: number,
 *            contrast: number,
 *            hue: number,
 *            opacity: number,
 *            saturation: number,
 *            sourceState: ol.source.State,
 *            visible: boolean,
 *            extent: (ol.Extent|undefined),
 *            maxResolution: number,
 *            minResolution: number}}
 */
ol.layer.LayerState;

/**
 * @classdesc
 * Abstract base class; normally only used for creating subclasses and not
 * instantiated in apps.
 * Note that with `ol.layer.Base` and all its subclasses, any property set in
 * the options is set as a {@link ol.Object} property on the layer object, so
 * is observable, and has get/set accessors.
 *
 * @constructor
 * @extends {ol.Object}
 * @param {olx.layer.BaseOptions} options Layer options.
 * @api stable
 */
ol.layer.Base = function(options) {

  goog.base(this);

  /**
   * @type {Object.<string, *>}
   */
  var properties = goog.object.clone(options);
  properties[ol.layer.LayerProperty.BRIGHTNESS] =
      goog.isDef(options.brightness) ? options.brightness : 0;
  properties[ol.layer.LayerProperty.CONTRAST] =
      goog.isDef(options.contrast) ? options.contrast : 1;
  properties[ol.layer.LayerProperty.HUE] =
      goog.isDef(options.hue) ? options.hue : 0;
  properties[ol.layer.LayerProperty.OPACITY] =
      goog.isDef(options.opacity) ? options.opacity : 1;
  properties[ol.layer.LayerProperty.SATURATION] =
      goog.isDef(options.saturation) ? options.saturation : 1;
  properties[ol.layer.LayerProperty.VISIBLE] =
      goog.isDef(options.visible) ? options.visible : true;
  properties[ol.layer.LayerProperty.MAX_RESOLUTION] =
      goog.isDef(options.maxResolution) ? options.maxResolution : Infinity;
  properties[ol.layer.LayerProperty.MIN_RESOLUTION] =
      goog.isDef(options.minResolution) ? options.minResolution : 0;

  this.setProperties(properties);
};
goog.inherits(ol.layer.Base, ol.Object);

/**
 * @return {number|undefined} The brightness of the layer.
 * @observable
 * @api
 */
ol.layer.Base.prototype.getBrightness = function() {
  return /** @type {number|undefined} */ (
      this.get(ol.layer.LayerProperty.BRIGHTNESS));
};
goog.exportProperty(
    ol.layer.Base.prototype,
    'getBrightness',
    ol.layer.Base.prototype.getBrightness);

/**
 * @return {number|undefined} The contrast of the layer.
 * @observable
 * @api
 */
ol.layer.Base.prototype.getContrast = function() {
  return /** @type {number|undefined} */ (
      this.get(ol.layer.LayerProperty.CONTRAST));
};
goog.exportProperty(
    ol.layer.Base.prototype,
    'getContrast',
    ol.layer.Base.prototype.getContrast);

/**
 * @return {number} The hue of the layer.
 * @observable
 * @api
 */
ol.layer.Base.prototype.getHue = function() {
  return /** @type {number} */ (this.get(ol.layer.LayerProperty.HUE));
};
goog.exportProperty(
    ol.layer.Base.prototype,
    'getHue',
    ol.layer.Base.prototype.getHue);

/**
 * @return {ol.layer.LayerState} Layer state.
 */
ol.layer.Base.prototype.getLayerState = function() {
  var brightness = this.getBrightness();
  var contrast = this.getContrast();
  var hue = this.getHue();
  var opacity = this.getOpacity();
  var saturation = this.getSaturation();
  var sourceState = this.getSourceState();
  var visible = this.getVisible();
  var extent = this.getExtent();
  var maxResolution = this.getMaxResolution();
  var minResolution = this.getMinResolution();
  return {
    layer: /** @type {ol.layer.Layer} */ (this),
    brightness: goog.isDef(brightness) ? goog.math.clamp(brightness, -1, 1) : 0,
    contrast: goog.isDef(contrast) ? Math.max(contrast, 0) : 1,
    hue: hue,
    opacity: goog.math.clamp(opacity, 0, 1),
    saturation: goog.isDef(saturation) ? Math.max(saturation, 0) : 1,
    sourceState: sourceState,
    visible: visible,
    extent: extent,
    maxResolution: goog.isDef(maxResolution) ? maxResolution : Infinity,
    minResolution: goog.isDef(minResolution) ? Math.max(minResolution, 0) : 0
  };
};

/**
 * @param {Array.<ol.layer.Layer>=} opt_array Array of layers (to be
 *     modified in place).
 * @return {Array.<ol.layer.Layer>} Array of layers.
 */
ol.layer.Base.prototype.getLayersArray = goog.abstractMethod;

/**
 * @param {Array.<ol.layer.LayerState>=} opt_states Optional list of layer
 *     states (to be modified in place).
 * @return {Array.<ol.layer.LayerState>} List of layer states.
 */
ol.layer.Base.prototype.getLayerStatesArray = goog.abstractMethod;

/**
 * @return {ol.Extent|undefined} The layer extent.
 * @observable
 * @api stable
 */
ol.layer.Base.prototype.getExtent = function() {
  return /** @type {ol.Extent|undefined} */ (
      this.get(ol.layer.LayerProperty.EXTENT));
};
goog.exportProperty(
    ol.layer.Base.prototype,
    'getExtent',
    ol.layer.Base.prototype.getExtent);

/**
 * @return {number|undefined} The maximum resolution of the layer.
 * @observable
 * @api stable
 */
ol.layer.Base.prototype.getMaxResolution = function() {
  return /** @type {number|undefined} */ (
      this.get(ol.layer.LayerProperty.MAX_RESOLUTION));
};
goog.exportProperty(
    ol.layer.Base.prototype,
    'getMaxResolution',
    ol.layer.Base.prototype.getMaxResolution);

/**
 * @return {number|undefined} The minimum resolution of the layer.
 * @observable
 * @api stable
 */
ol.layer.Base.prototype.getMinResolution = function() {
  return /** @type {number|undefined} */ (
      this.get(ol.layer.LayerProperty.MIN_RESOLUTION));
};
goog.exportProperty(
    ol.layer.Base.prototype,
    'getMinResolution',
    ol.layer.Base.prototype.getMinResolution);

/**
 * @return {number} The opacity of the layer.
 * @observable
 * @api stable
 */
ol.layer.Base.prototype.getOpacity = function() {
  return /** @type {number} */ (this.get(ol.layer.LayerProperty.OPACITY));
};
goog.exportProperty(
    ol.layer.Base.prototype,
    'getOpacity',
    ol.layer.Base.prototype.getOpacity);

/**
 * @return {number|undefined} The saturation of the layer.
 * @observable
 * @api
 */
ol.layer.Base.prototype.getSaturation = function() {
  return /** @type {number|undefined} */ (
      this.get(ol.layer.LayerProperty.SATURATION));
};
goog.exportProperty(
    ol.layer.Base.prototype,
    'getSaturation',
    ol.layer.Base.prototype.getSaturation);

/**
 * @return {ol.source.State} Source state.
 */
ol.layer.Base.prototype.getSourceState = goog.abstractMethod;

/**
 * @return {boolean} The visibility of the layer.
 * @observable
 * @api stable
 */
ol.layer.Base.prototype.getVisible = function() {
  return /** @type {boolean} */ (this.get(ol.layer.LayerProperty.VISIBLE));
};
goog.exportProperty(
    ol.layer.Base.prototype,
    'getVisible',
    ol.layer.Base.prototype.getVisible);

/**
 * Adjust the layer brightness.  A value of -1 will render the layer completely
 * black.  A value of 0 will leave the brightness unchanged.  A value of 1 will
 * render the layer completely white.  Other values are linear multipliers on
 * the effect (values are clamped between -1 and 1).
 *
 * The filter effects draft [1] says the brightness function is supposed to
 * render 0 black, 1 unchanged, and all other values as a linear multiplier.
 *
 * The current WebKit implementation clamps values between -1 (black) and 1
 * (white) [2].  There is a bug open to change the filter effect spec [3].
 *
 * TODO: revisit this if the spec is still unmodified before we release
 *
 * [1] https://dvcs.w3.org/hg/FXTF/raw-file/tip/filters/index.html
 * [2] https://github.com/WebKit/webkit/commit/8f4765e569
 * [3] https://www.w3.org/Bugs/Public/show_bug.cgi?id=15647
 *
 * @param {number|undefined} brightness The brightness of the layer.
 * @observable
 * @api
 */
ol.layer.Base.prototype.setBrightness = function(brightness) {
  this.set(ol.layer.LayerProperty.BRIGHTNESS, brightness);
};
goog.exportProperty(
    ol.layer.Base.prototype,
    'setBrightness',
    ol.layer.Base.prototype.setBrightness);

/**
 * Adjust the layer contrast.  A value of 0 will render the layer completely
 * grey.  A value of 1 will leave the contrast unchanged.  Other values are
 * linear multipliers on the effect (and values over 1 are permitted).
 *
 * @param {number|undefined} contrast The contrast of the layer.
 * @observable
 * @api
 */
ol.layer.Base.prototype.setContrast = function(contrast) {
  this.set(ol.layer.LayerProperty.CONTRAST, contrast);
};
goog.exportProperty(
    ol.layer.Base.prototype,
    'setContrast',
    ol.layer.Base.prototype.setContrast);

/**
 * Apply a hue-rotation to the layer.  A value of 0 will leave the hue
 * unchanged.  Other values are radians around the color circle.
 * @param {number} hue The hue of the layer.
 * @observable
 * @api
 */
ol.layer.Base.prototype.setHue = function(hue) {
  this.set(ol.layer.LayerProperty.HUE, hue);
};
goog.exportProperty(
    ol.layer.Base.prototype,
    'setHue',
    ol.layer.Base.prototype.setHue);

/**
 * Set the extent at which the layer is visible.  If `undefined`, the layer
 * will be visible at all extents.
 * @param {ol.Extent|undefined} extent The extent of the layer.
 * @observable
 * @api stable
 */
ol.layer.Base.prototype.setExtent = function(extent) {
  this.set(ol.layer.LayerProperty.EXTENT, extent);
};
goog.exportProperty(
    ol.layer.Base.prototype,
    'setExtent',
    ol.layer.Base.prototype.setExtent);

/**
 * @param {number|undefined} maxResolution The maximum resolution of the layer.
 * @observable
 * @api stable
 */
ol.layer.Base.prototype.setMaxResolution = function(maxResolution) {
  this.set(ol.layer.LayerProperty.MAX_RESOLUTION, maxResolution);
};
goog.exportProperty(
    ol.layer.Base.prototype,
    'setMaxResolution',
    ol.layer.Base.prototype.setMaxResolution);

/**
 * @param {number|undefined} minResolution The minimum resolution of the layer.
 * @observable
 * @api stable
 */
ol.layer.Base.prototype.setMinResolution = function(minResolution) {
  this.set(ol.layer.LayerProperty.MIN_RESOLUTION, minResolution);
};
goog.exportProperty(
    ol.layer.Base.prototype,
    'setMinResolution',
    ol.layer.Base.prototype.setMinResolution);

/**
 * @param {number} opacity The opacity of the layer.
 * @observable
 * @api stable
 */
ol.layer.Base.prototype.setOpacity = function(opacity) {
  this.set(ol.layer.LayerProperty.OPACITY, opacity);
};
goog.exportProperty(
    ol.layer.Base.prototype,
    'setOpacity',
    ol.layer.Base.prototype.setOpacity);

/**
 * Adjust layer saturation.  A value of 0 will render the layer completely
 * unsaturated.  A value of 1 will leave the saturation unchanged.  Other
 * values are linear multipliers of the effect (and values over 1 are
 * permitted).
 *
 * @param {number|undefined} saturation The saturation of the layer.
 * @observable
 * @api
 */
ol.layer.Base.prototype.setSaturation = function(saturation) {
  this.set(ol.layer.LayerProperty.SATURATION, saturation);
};
goog.exportProperty(
    ol.layer.Base.prototype,
    'setSaturation',
    ol.layer.Base.prototype.setSaturation);

/**
 * @param {boolean} visible The visibility of the layer.
 * @observable
 * @api stable
 */
ol.layer.Base.prototype.setVisible = function(visible) {
  this.set(ol.layer.LayerProperty.VISIBLE, visible);
};
goog.exportProperty(
    ol.layer.Base.prototype,
    'setVisible',
    ol.layer.Base.prototype.setVisible);
<commit_msg>Disallowed undefined 'brightness' value<commit_after>goog.provide('ol.layer.Base');
goog.provide('ol.layer.LayerProperty');
goog.provide('ol.layer.LayerState');

goog.require('goog.events');
goog.require('goog.math');
goog.require('goog.object');
goog.require('ol.Object');
goog.require('ol.source.State');

/**
 * @enum {string}
 */
ol.layer.LayerProperty = {
  BRIGHTNESS: 'brightness',
  CONTRAST: 'contrast',
  HUE: 'hue',
  OPACITY: 'opacity',
  SATURATION: 'saturation',
  VISIBLE: 'visible',
  EXTENT: 'extent',
  MAX_RESOLUTION: 'maxResolution',
  MIN_RESOLUTION: 'minResolution',
  SOURCE: 'source'
};

/**
 * @typedef {{layer: ol.layer.Layer,
 *            brightness: number,
 *            contrast: number,
 *            hue: number,
 *            opacity: number,
 *            saturation: number,
 *            sourceState: ol.source.State,
 *            visible: boolean,
 *            extent: (ol.Extent|undefined),
 *            maxResolution: number,
 *            minResolution: number}}
 */
ol.layer.LayerState;

/**
 * @classdesc
 * Abstract base class; normally only used for creating subclasses and not
 * instantiated in apps.
 * Note that with `ol.layer.Base` and all its subclasses, any property set in
 * the options is set as a {@link ol.Object} property on the layer object, so
 * is observable, and has get/set accessors.
 *
 * @constructor
 * @extends {ol.Object}
 * @param {olx.layer.BaseOptions} options Layer options.
 * @api stable
 */
ol.layer.Base = function(options) {

  goog.base(this);

  /**
   * @type {Object.<string, *>}
   */
  var properties = goog.object.clone(options);
  properties[ol.layer.LayerProperty.BRIGHTNESS] =
      goog.isDef(options.brightness) ? options.brightness : 0;
  properties[ol.layer.LayerProperty.CONTRAST] =
      goog.isDef(options.contrast) ? options.contrast : 1;
  properties[ol.layer.LayerProperty.HUE] =
      goog.isDef(options.hue) ? options.hue : 0;
  properties[ol.layer.LayerProperty.OPACITY] =
      goog.isDef(options.opacity) ? options.opacity : 1;
  properties[ol.layer.LayerProperty.SATURATION] =
      goog.isDef(options.saturation) ? options.saturation : 1;
  properties[ol.layer.LayerProperty.VISIBLE] =
      goog.isDef(options.visible) ? options.visible : true;
  properties[ol.layer.LayerProperty.MAX_RESOLUTION] =
      goog.isDef(options.maxResolution) ? options.maxResolution : Infinity;
  properties[ol.layer.LayerProperty.MIN_RESOLUTION] =
      goog.isDef(options.minResolution) ? options.minResolution : 0;

  this.setProperties(properties);
};
goog.inherits(ol.layer.Base, ol.Object);

/**
 * @return {number} The brightness of the layer.
 * @observable
 * @api
 */
ol.layer.Base.prototype.getBrightness = function() {
  return /** @type {number} */ (this.get(ol.layer.LayerProperty.BRIGHTNESS));
};
goog.exportProperty(
    ol.layer.Base.prototype,
    'getBrightness',
    ol.layer.Base.prototype.getBrightness);

/**
 * @return {number|undefined} The contrast of the layer.
 * @observable
 * @api
 */
ol.layer.Base.prototype.getContrast = function() {
  return /** @type {number|undefined} */ (
      this.get(ol.layer.LayerProperty.CONTRAST));
};
goog.exportProperty(
    ol.layer.Base.prototype,
    'getContrast',
    ol.layer.Base.prototype.getContrast);

/**
 * @return {number} The hue of the layer.
 * @observable
 * @api
 */
ol.layer.Base.prototype.getHue = function() {
  return /** @type {number} */ (this.get(ol.layer.LayerProperty.HUE));
};
goog.exportProperty(
    ol.layer.Base.prototype,
    'getHue',
    ol.layer.Base.prototype.getHue);

/**
 * @return {ol.layer.LayerState} Layer state.
 */
ol.layer.Base.prototype.getLayerState = function() {
  var brightness = this.getBrightness();
  var contrast = this.getContrast();
  var hue = this.getHue();
  var opacity = this.getOpacity();
  var saturation = this.getSaturation();
  var sourceState = this.getSourceState();
  var visible = this.getVisible();
  var extent = this.getExtent();
  var maxResolution = this.getMaxResolution();
  var minResolution = this.getMinResolution();
  return {
    layer: /** @type {ol.layer.Layer} */ (this),
    brightness: goog.math.clamp(brightness, -1, 1),
    contrast: goog.isDef(contrast) ? Math.max(contrast, 0) : 1,
    hue: hue,
    opacity: goog.math.clamp(opacity, 0, 1),
    saturation: goog.isDef(saturation) ? Math.max(saturation, 0) : 1,
    sourceState: sourceState,
    visible: visible,
    extent: extent,
    maxResolution: goog.isDef(maxResolution) ? maxResolution : Infinity,
    minResolution: goog.isDef(minResolution) ? Math.max(minResolution, 0) : 0
  };
};

/**
 * @param {Array.<ol.layer.Layer>=} opt_array Array of layers (to be
 *     modified in place).
 * @return {Array.<ol.layer.Layer>} Array of layers.
 */
ol.layer.Base.prototype.getLayersArray = goog.abstractMethod;

/**
 * @param {Array.<ol.layer.LayerState>=} opt_states Optional list of layer
 *     states (to be modified in place).
 * @return {Array.<ol.layer.LayerState>} List of layer states.
 */
ol.layer.Base.prototype.getLayerStatesArray = goog.abstractMethod;

/**
 * @return {ol.Extent|undefined} The layer extent.
 * @observable
 * @api stable
 */
ol.layer.Base.prototype.getExtent = function() {
  return /** @type {ol.Extent|undefined} */ (
      this.get(ol.layer.LayerProperty.EXTENT));
};
goog.exportProperty(
    ol.layer.Base.prototype,
    'getExtent',
    ol.layer.Base.prototype.getExtent);

/**
 * @return {number|undefined} The maximum resolution of the layer.
 * @observable
 * @api stable
 */
ol.layer.Base.prototype.getMaxResolution = function() {
  return /** @type {number|undefined} */ (
      this.get(ol.layer.LayerProperty.MAX_RESOLUTION));
};
goog.exportProperty(
    ol.layer.Base.prototype,
    'getMaxResolution',
    ol.layer.Base.prototype.getMaxResolution);

/**
 * @return {number|undefined} The minimum resolution of the layer.
 * @observable
 * @api stable
 */
ol.layer.Base.prototype.getMinResolution = function() {
  return /** @type {number|undefined} */ (
      this.get(ol.layer.LayerProperty.MIN_RESOLUTION));
};
goog.exportProperty(
    ol.layer.Base.prototype,
    'getMinResolution',
    ol.layer.Base.prototype.getMinResolution);

/**
 * @return {number} The opacity of the layer.
 * @observable
 * @api stable
 */
ol.layer.Base.prototype.getOpacity = function() {
  return /** @type {number} */ (this.get(ol.layer.LayerProperty.OPACITY));
};
goog.exportProperty(
    ol.layer.Base.prototype,
    'getOpacity',
    ol.layer.Base.prototype.getOpacity);

/**
 * @return {number|undefined} The saturation of the layer.
 * @observable
 * @api
 */
ol.layer.Base.prototype.getSaturation = function() {
  return /** @type {number|undefined} */ (
      this.get(ol.layer.LayerProperty.SATURATION));
};
goog.exportProperty(
    ol.layer.Base.prototype,
    'getSaturation',
    ol.layer.Base.prototype.getSaturation);

/**
 * @return {ol.source.State} Source state.
 */
ol.layer.Base.prototype.getSourceState = goog.abstractMethod;

/**
 * @return {boolean} The visibility of the layer.
 * @observable
 * @api stable
 */
ol.layer.Base.prototype.getVisible = function() {
  return /** @type {boolean} */ (this.get(ol.layer.LayerProperty.VISIBLE));
};
goog.exportProperty(
    ol.layer.Base.prototype,
    'getVisible',
    ol.layer.Base.prototype.getVisible);

/**
 * Adjust the layer brightness.  A value of -1 will render the layer completely
 * black.  A value of 0 will leave the brightness unchanged.  A value of 1 will
 * render the layer completely white.  Other values are linear multipliers on
 * the effect (values are clamped between -1 and 1).
 *
 * The filter effects draft [1] says the brightness function is supposed to
 * render 0 black, 1 unchanged, and all other values as a linear multiplier.
 *
 * The current WebKit implementation clamps values between -1 (black) and 1
 * (white) [2].  There is a bug open to change the filter effect spec [3].
 *
 * TODO: revisit this if the spec is still unmodified before we release
 *
 * [1] https://dvcs.w3.org/hg/FXTF/raw-file/tip/filters/index.html
 * [2] https://github.com/WebKit/webkit/commit/8f4765e569
 * [3] https://www.w3.org/Bugs/Public/show_bug.cgi?id=15647
 *
 * @param {number} brightness The brightness of the layer.
 * @observable
 * @api
 */
ol.layer.Base.prototype.setBrightness = function(brightness) {
  this.set(ol.layer.LayerProperty.BRIGHTNESS, brightness);
};
goog.exportProperty(
    ol.layer.Base.prototype,
    'setBrightness',
    ol.layer.Base.prototype.setBrightness);

/**
 * Adjust the layer contrast.  A value of 0 will render the layer completely
 * grey.  A value of 1 will leave the contrast unchanged.  Other values are
 * linear multipliers on the effect (and values over 1 are permitted).
 *
 * @param {number|undefined} contrast The contrast of the layer.
 * @observable
 * @api
 */
ol.layer.Base.prototype.setContrast = function(contrast) {
  this.set(ol.layer.LayerProperty.CONTRAST, contrast);
};
goog.exportProperty(
    ol.layer.Base.prototype,
    'setContrast',
    ol.layer.Base.prototype.setContrast);

/**
 * Apply a hue-rotation to the layer.  A value of 0 will leave the hue
 * unchanged.  Other values are radians around the color circle.
 * @param {number} hue The hue of the layer.
 * @observable
 * @api
 */
ol.layer.Base.prototype.setHue = function(hue) {
  this.set(ol.layer.LayerProperty.HUE, hue);
};
goog.exportProperty(
    ol.layer.Base.prototype,
    'setHue',
    ol.layer.Base.prototype.setHue);

/**
 * Set the extent at which the layer is visible.  If `undefined`, the layer
 * will be visible at all extents.
 * @param {ol.Extent|undefined} extent The extent of the layer.
 * @observable
 * @api stable
 */
ol.layer.Base.prototype.setExtent = function(extent) {
  this.set(ol.layer.LayerProperty.EXTENT, extent);
};
goog.exportProperty(
    ol.layer.Base.prototype,
    'setExtent',
    ol.layer.Base.prototype.setExtent);

/**
 * @param {number|undefined} maxResolution The maximum resolution of the layer.
 * @observable
 * @api stable
 */
ol.layer.Base.prototype.setMaxResolution = function(maxResolution) {
  this.set(ol.layer.LayerProperty.MAX_RESOLUTION, maxResolution);
};
goog.exportProperty(
    ol.layer.Base.prototype,
    'setMaxResolution',
    ol.layer.Base.prototype.setMaxResolution);

/**
 * @param {number|undefined} minResolution The minimum resolution of the layer.
 * @observable
 * @api stable
 */
ol.layer.Base.prototype.setMinResolution = function(minResolution) {
  this.set(ol.layer.LayerProperty.MIN_RESOLUTION, minResolution);
};
goog.exportProperty(
    ol.layer.Base.prototype,
    'setMinResolution',
    ol.layer.Base.prototype.setMinResolution);

/**
 * @param {number} opacity The opacity of the layer.
 * @observable
 * @api stable
 */
ol.layer.Base.prototype.setOpacity = function(opacity) {
  this.set(ol.layer.LayerProperty.OPACITY, opacity);
};
goog.exportProperty(
    ol.layer.Base.prototype,
    'setOpacity',
    ol.layer.Base.prototype.setOpacity);

/**
 * Adjust layer saturation.  A value of 0 will render the layer completely
 * unsaturated.  A value of 1 will leave the saturation unchanged.  Other
 * values are linear multipliers of the effect (and values over 1 are
 * permitted).
 *
 * @param {number|undefined} saturation The saturation of the layer.
 * @observable
 * @api
 */
ol.layer.Base.prototype.setSaturation = function(saturation) {
  this.set(ol.layer.LayerProperty.SATURATION, saturation);
};
goog.exportProperty(
    ol.layer.Base.prototype,
    'setSaturation',
    ol.layer.Base.prototype.setSaturation);

/**
 * @param {boolean} visible The visibility of the layer.
 * @observable
 * @api stable
 */
ol.layer.Base.prototype.setVisible = function(visible) {
  this.set(ol.layer.LayerProperty.VISIBLE, visible);
};
goog.exportProperty(
    ol.layer.Base.prototype,
    'setVisible',
    ol.layer.Base.prototype.setVisible);
<|endoftext|>


<commit_before>// FIXME decide default value for snapToPixel

goog.provide('ol.style.Icon');

goog.require('goog.array');
goog.require('goog.asserts');
goog.require('goog.events');
goog.require('goog.events.EventType');
goog.require('ol.style.Image');
goog.require('ol.style.ImageState');

/**
 * @constructor
 * @param {olx.style.IconOptions=} opt_options Options.
 * @extends {ol.style.Image}
 */
ol.style.Icon = function(opt_options) {

  var options = goog.isDef(opt_options) ? opt_options : {};

  /**
   * @private
   * @type {Image}
   */
  this.image_ = new Image();

  /**
   * @type {?string}
   */
  var crossOrigin =
      goog.isDef(options.crossOrigin) ? options.crossOrigin : null;
  if (!goog.isNull(crossOrigin)) {
    this.image_.crossOrigin = crossOrigin;
  }

  /**
   * @private
   * @type {Array.<number>}
   */
  this.imageListenerKeys_ = null;

  /**
   * @private
   * @type {string|undefined}
   */
  this.src_ = options.src;

  /**
   * @type {ol.Size}
   */
  var size = goog.isDef(options.size) ? options.size : null;

  /**
   * @type {ol.Pixel}
   */
  var anchor;
  if (goog.isDef(options.anchor)) {
    anchor = options.anchor;
  } else if (!goog.isNull(size)) {
    anchor = [size[0] / 2, size[1] / 2];
  } else {
    anchor = null;
  }

  /**
   * @type {number}
   */
  var rotation = goog.isDef(options.rotation) ? options.rotation : 0;

  goog.base(this, {
    anchor: anchor,
    imageState: ol.style.ImageState.IDLE,
    rotation: rotation,
    size: size,
    snapToPixel: undefined,
    subtractViewRotation: false
  });

};
goog.inherits(ol.style.Icon, ol.style.Image);

/**
 * @private
 */
ol.style.Icon.prototype.handleImageError_ = function() {
  this.imageState = ol.style.ImageState.ERROR;
  this.unlistenImage_();
  this.dispatchChangeEvent();
};

/**
 * @private
 */
ol.style.Icon.prototype.handleImageLoad_ = function() {
  this.imageState = ol.style.ImageState.LOADED;
  if (goog.isNull(this.size)) {
    this.size = [this.image_.width, this.image_.height];
  }
  if (goog.isNull(this.anchor)) {
    this.anchor = [this.size[0] / 2, this.size[1] / 2];
  }
  this.unlistenImage_();
  this.dispatchChangeEvent();
};

/**
 * @inheritDoc
 */
ol.style.Icon.prototype.getImage = function(pixelRatio) {
  return this.image_;
};

/**
 * Load not yet loaded URI.
 */
ol.style.Icon.prototype.load = function() {
  if (this.imageState == ol.style.ImageState.IDLE) {
    goog.asserts.assert(goog.isDef(this.src_));
    goog.asserts.assert(goog.isNull(this.imageListenerKeys_));
    this.imageState = ol.style.ImageState.LOADING;
    this.imageListenerKeys_ = [
      goog.events.listenOnce(this.image_, goog.events.EventType.ERROR,
          this.handleImageError_, false, this),
      goog.events.listenOnce(this.image_, goog.events.EventType.LOAD,
          this.handleImageLoad_, false, this)
    ];
    this.image_.src = this.src_;
  }
};

/**
 * Discards event handlers which listen for load completion or errors.
 *
 * @private
 */
ol.style.Icon.prototype.unlistenImage_ = function() {
  goog.asserts.assert(!goog.isNull(this.imageListenerKeys_));
  goog.array.forEach(this.imageListenerKeys_, goog.events.unlistenByKey);
  this.imageListenerKeys_ = null;
};
<commit_msg>Add ol.style.Icon#getHitDetectionImage<commit_after>// FIXME decide default value for snapToPixel

goog.provide('ol.style.Icon');

goog.require('goog.array');
goog.require('goog.asserts');
goog.require('goog.dom');
goog.require('goog.dom.TagName');
goog.require('goog.events');
goog.require('goog.events.EventType');
goog.require('ol.style.Image');
goog.require('ol.style.ImageState');

/**
 * @constructor
 * @param {olx.style.IconOptions=} opt_options Options.
 * @extends {ol.style.Image}
 */
ol.style.Icon = function(opt_options) {

  var options = goog.isDef(opt_options) ? opt_options : {};

  /**
   * @private
   * @type {Image|HTMLCanvasElement}
   */
  this.hitDetectionImage_ = null;

  /**
   * @private
   * @type {Image}
   */
  this.image_ = new Image();

  /**
   * @type {?string}
   */
  var crossOrigin =
      goog.isDef(options.crossOrigin) ? options.crossOrigin : null;
  if (!goog.isNull(crossOrigin)) {
    this.image_.crossOrigin = crossOrigin;
  }

  /**
   * @private
   * @type {Array.<number>}
   */
  this.imageListenerKeys_ = null;

  /**
   * @private
   * @type {string|undefined}
   */
  this.src_ = options.src;

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

  /**
   * @type {ol.Size}
   */
  var size = goog.isDef(options.size) ? options.size : null;

  /**
   * @type {ol.Pixel}
   */
  var anchor;
  if (goog.isDef(options.anchor)) {
    anchor = options.anchor;
  } else if (!goog.isNull(size)) {
    anchor = [size[0] / 2, size[1] / 2];
  } else {
    anchor = null;
  }

  /**
   * @type {number}
   */
  var rotation = goog.isDef(options.rotation) ? options.rotation : 0;

  goog.base(this, {
    anchor: anchor,
    imageState: ol.style.ImageState.IDLE,
    rotation: rotation,
    size: size,
    snapToPixel: undefined,
    subtractViewRotation: false
  });

};
goog.inherits(ol.style.Icon, ol.style.Image);

/**
 * @private
 */
ol.style.Icon.prototype.determineTainting_ = function() {
  var canvas = /** @type {HTMLCanvasElement} */
      (goog.dom.createElement(goog.dom.TagName.CANVAS));
  canvas.width = 1;
  canvas.height = 1;
  var context = /** @type {CanvasRenderingContext2D} */
      (canvas.getContext('2d'));
  context.drawImage(this.image_, 0, 0);
  try {
    context.getImageData(0, 0, 1, 1);
  } catch (e) {
    this.tainting_ = true;
  }
};

/**
 * @private
 */
ol.style.Icon.prototype.handleImageError_ = function() {
  this.imageState = ol.style.ImageState.ERROR;
  this.unlistenImage_();
  this.dispatchChangeEvent();
};

/**
 * @private
 */
ol.style.Icon.prototype.handleImageLoad_ = function() {
  this.imageState = ol.style.ImageState.LOADED;
  if (goog.isNull(this.size)) {
    this.size = [this.image_.width, this.image_.height];
  }
  if (goog.isNull(this.anchor)) {
    this.anchor = [this.size[0] / 2, this.size[1] / 2];
  }
  this.unlistenImage_();
  this.determineTainting_();
  this.dispatchChangeEvent();
};

/**
 * @inheritDoc
 */
ol.style.Icon.prototype.getImage = function(pixelRatio) {
  return this.image_;
};

/**
 * @inheritDoc
 */
ol.style.Icon.prototype.getHitDetectionImage = function(pixelRatio) {
  if (goog.isNull(this.hitDetectionImage_)) {
    if (this.tainting_) {
      var canvas = /** @type {HTMLCanvasElement} */
          (goog.dom.createElement(goog.dom.TagName.CANVAS));
      var width = this.size[0];
      var height = this.size[1];
      canvas.width = width;
      canvas.height = height;
      var context = /** @type {CanvasRenderingContext2D} */
          (canvas.getContext('2d'));
      context.fillRect(0, 0, width, height);
      this.hitDetectionImage_ = canvas;
    } else {
      this.hitDetectionImage_ = this.image_;
    }
  }
  return this.hitDetectionImage_;
};

/**
 * Load not yet loaded URI.
 */
ol.style.Icon.prototype.load = function() {
  if (this.imageState == ol.style.ImageState.IDLE) {
    goog.asserts.assert(goog.isDef(this.src_));
    goog.asserts.assert(goog.isNull(this.imageListenerKeys_));
    this.imageState = ol.style.ImageState.LOADING;
    this.imageListenerKeys_ = [
      goog.events.listenOnce(this.image_, goog.events.EventType.ERROR,
          this.handleImageError_, false, this),
      goog.events.listenOnce(this.image_, goog.events.EventType.LOAD,
          this.handleImageLoad_, false, this)
    ];
    this.image_.src = this.src_;
  }
};

/**
 * Discards event handlers which listen for load completion or errors.
 *
 * @private
 */
ol.style.Icon.prototype.unlistenImage_ = function() {
  goog.asserts.assert(!goog.isNull(this.imageListenerKeys_));
  goog.array.forEach(this.imageListenerKeys_, goog.events.unlistenByKey);
  this.imageListenerKeys_ = null;
};
<|endoftext|>


<commit_before>/* eslint-disable no-console */

import React, { useEffect, useState } from 'react';

import UserRepo from '../container/UserRepo';
import fetchGithubApi from './fetchGithubApi';

const lastCommitMock = require('./lastCommitMock.json');

const repoName = 'dashboard';
const repoOwnerLogin = 'lowsky';
const repoPath = 'lowsky/dashboard';

const githubData = {
    repo: {
        owner: { login: repoOwnerLogin },
        name: repoName,
        branches: [],
    },
    user: {
        avatar_url: '//lorempixel.com/200/200/cats/lorempixel/',
        login: 'lowsky',
    },
    errorMsg: '',
};

export default () => {
    const [repo, storeRepo] = useState(githubData.repo);
    const [user, storeUser] = useState(githubData.user);
    const [errorMsg, storeErrorMsg] = useState(githubData.errorMsg);

    const loadUser = ({ fetchUser }) => {
        fetchUser(repoOwnerLogin)
            .then(user => {
                if (user.message) {
                    throw new Error(user.message);
                }
                storeUser(user);
            })
            .catch(ex => {
                storeErrorMsg('User: ' + ex.message);
                console.log('fetching user info failed', ex);
            });
    };

    const loadRepoBranches = ({ fetchRepoBranches }) => {
        fetchRepoBranches(repoPath)
            .then(branches => {
                if (branches.message) {
                    throw new Error(branches.message);
                }
                storeRepo({
                    owner: { login: repoOwnerLogin },
                    name: repoName,
                    branches: branches.map(b => ({ ...b, lastCommit: lastCommitMock })),
                });
            })
            .catch(ex => {
                storeErrorMsg('Repo: ' + ex.message);
                console.log('fetching branches info failed', ex);
            });
    };

    useEffect(() => loadUser(fetchGithubApi), [repoOwnerLogin]);
    useEffect(() => loadRepoBranches(fetchGithubApi), [repoPath]);

    return (

                {(user.loading || repo.loading) && (

                )}
                <UserRepo github={{ user, repo }} />

            {errorMsg &&
 {errorMsg}
}

    );
};
<commit_msg>fix eslint rule violation: react/display-name<commit_after>/* eslint-disable no-console */

import React, { useEffect, useState } from 'react';

import UserRepo from '../container/UserRepo';
import fetchGithubApi from './fetchGithubApi';

const lastCommitMock = require('./lastCommitMock.json');

const repoName = 'dashboard';
const repoOwnerLogin = 'lowsky';
const repoPath = 'lowsky/dashboard';

const githubData = {
    repo: {
        owner: { login: repoOwnerLogin },
        name: repoName,
        branches: [],
    },
    user: {
        avatar_url: '//lorempixel.com/200/200/cats/lorempixel/',
        login: 'lowsky',
    },
    errorMsg: '',
};

const RestfulPage = () => {
    const [repo, storeRepo] = useState(githubData.repo);
    const [user, storeUser] = useState(githubData.user);
    const [errorMsg, storeErrorMsg] = useState(githubData.errorMsg);

    const loadUser = ({ fetchUser }) => {
        fetchUser(repoOwnerLogin)
            .then(user => {
                if (user.message) {
                    throw new Error(user.message);
                }
                storeUser(user);
            })
            .catch(ex => {
                storeErrorMsg('User: ' + ex.message);
                console.log('fetching user info failed', ex);
            });
    };

    const loadRepoBranches = ({ fetchRepoBranches }) => {
        fetchRepoBranches(repoPath)
            .then(branches => {
                if (branches.message) {
                    throw new Error(branches.message);
                }
                storeRepo({
                    owner: { login: repoOwnerLogin },
                    name: repoName,
                    branches: branches.map(b => ({ ...b, lastCommit: lastCommitMock })),
                });
            })
            .catch(ex => {
                storeErrorMsg('Repo: ' + ex.message);
                console.log('fetching branches info failed', ex);
            });
    };

    useEffect(() => loadUser(fetchGithubApi), []);
    useEffect(() => loadRepoBranches(fetchGithubApi), []);

    return (

                {(user.loading || repo.loading) && (

                )}
                <UserRepo github={{ user, repo }} />

            {errorMsg &&
 {errorMsg}
}

    );
};
export default RestfulPage;
<|endoftext|>


<commit_before>// @flow strict-local

import React from "preact";
import Shadow from "preact-shadow-root";

import {
  CSS,
  HIDDEN_CLASS,
  HIGHLIGHTED_HINT_CLASS,
  HINT_CLASS,
  MATCHED_CHARS_CLASS,
  MAX_Z_INDEX,
  MIN_Z_INDEX,
  MIXED_CASE_CLASS,
  PEEK_CLASS,
  ROOT_CLASS,
  SHRUGGIE,
  STATUS_CLASS,
  TEXT_RECT_CLASS,
} from "../shared/css";
import {
  type Box,
  classlist,
  getTextRects,
  isMixedCase,
  splitEnteredText,
} from "../shared/main";

const HINT_X = 38; // px
const HINT_Y = 50; // px
const HINT_X_OFFSET = 10; // px
const HINT_Y_OFFSET = 10; // px

const HINT_VARIATIONS = [
  [[0, 1], [1, 0]],
  [[0, 2], [1, 1], [2, 0]],
  [[0, 3], [2, 1], [3, 0]],
];

const FILTER_BY_TEXT = (

    Nearby example TEXT{" "}
    to filter.

);
const ENTERED_TEXT = "filter by text ex";

type Props = {|
  chars: string,
  css: string,
  peek: boolean,
|};

type State = {|
  textRects: Array<Box>,
|};

export default class CSSPreview extends React.Component<Props, State> {
  containerRef: { current: HTMLDivElement | null };
  filterByText: { current: HTMLDivElement | null };

  constructor(props: Props) {
    super(props);

    this.containerRef = React.createRef();
    this.filterByText = React.createRef();

    this.state = {
      textRects: [],
    };
  }

  componentDidMount() {
    this.updateTextRects();
  }

  updateTextRects() {
    const containerElement = this.containerRef.current;
    const filterByTextElement = this.filterByText.current;
    if (containerElement == null || filterByTextElement == null) {
      return;
    }

    const rect = containerElement.getBoundingClientRect();

    const textRects = getTextRects({
      element: filterByTextElement,
      viewports: [],
      words: new Set(splitEnteredText(ENTERED_TEXT)),
      checkElementAtPoint: false,
    }).map(box => ({
      ...box,
      x: box.x - rect.left,
      y: box.y - rect.top,
    }));

    this.setState({ textRects });
  }

  render() {
    const { chars, css, peek } = this.props;
    const { textRects } = this.state;

    let hintZIndex = MAX_Z_INDEX;
    const hint = ({
      left,
      top,
      matchedChars = "",
      chars: unmatchedChars,
      highlighted = false,
      hidden = false,
    }: {|
      /* eslint-disable react/require-default-props */
      left: number,
      top: number,
      matchedChars?: string,
      chars: string,
      highlighted?: boolean,
      hidden?: boolean,
      /* eslint-enable react/require-default-props */
    |}) => {
      hintZIndex--;
      return (

          {matchedChars.length > 0 && (
            {matchedChars}
          )}
          {unmatchedChars}

      );
    };

    return (

          {FILTER_BY_TEXT}

          <Shadow>

              {hint({
                left: 0,
                top: HINT_Y * (HINT_VARIATIONS.length + 1),
                chars: SHRUGGIE,
              })}

              {hint({
                left: HINT_X * 2,
                top: HINT_Y * (HINT_VARIATIONS.length + 1),
                chars: "hidden",
                hidden: true,
              })}

                {ENTERED_TEXT}

              {chars.split("").map((char, index) =>
                hint({
                  left: HINT_X * index,
                  top: 0,
                  chars: char,
                })
              )}

              {HINT_VARIATIONS.map((variations, y) =>
                []
                  .concat(
                    ...variations.map(([numMatched, numChars]) =>
                      [false, true].map(highlighted => ({
                        matchedChars: chars.slice(0, numMatched),
                        chars: chars.slice(
                          numMatched,
                          numMatched + numChars
                        ),
                        highlighted,
                      }))
                    )
                  )
                  .map((props, x) =>
                    hint({
                      left: HINT_X * 2 * x,
                      top: HINT_Y * (y + 1),
                      ...props,
                    })
                  )
              )}

              {textRects.map((box, index) => (

              ))}

          </Shadow>

    );
  }
}
<commit_msg>Run Prettier<commit_after>// @flow strict-local

import React from "preact";
import Shadow from "preact-shadow-root";

import {
  CSS,
  HIDDEN_CLASS,
  HIGHLIGHTED_HINT_CLASS,
  HINT_CLASS,
  MATCHED_CHARS_CLASS,
  MAX_Z_INDEX,
  MIN_Z_INDEX,
  MIXED_CASE_CLASS,
  PEEK_CLASS,
  ROOT_CLASS,
  SHRUGGIE,
  STATUS_CLASS,
  TEXT_RECT_CLASS,
} from "../shared/css";
import {
  type Box,
  classlist,
  getTextRects,
  isMixedCase,
  splitEnteredText,
} from "../shared/main";

const HINT_X = 38; // px
const HINT_Y = 50; // px
const HINT_X_OFFSET = 10; // px
const HINT_Y_OFFSET = 10; // px

const HINT_VARIATIONS = [
  [[0, 1], [1, 0]],
  [[0, 2], [1, 1], [2, 0]],
  [[0, 3], [2, 1], [3, 0]],
];

const FILTER_BY_TEXT = (

    Nearby example TEXT{" "}
    to filter.

);
const ENTERED_TEXT = "filter by text ex";

type Props = {|
  chars: string,
  css: string,
  peek: boolean,
|};

type State = {|
  textRects: Array<Box>,
|};

export default class CSSPreview extends React.Component<Props, State> {
  containerRef: { current: HTMLDivElement | null };
  filterByText: { current: HTMLDivElement | null };

  constructor(props: Props) {
    super(props);

    this.containerRef = React.createRef();
    this.filterByText = React.createRef();

    this.state = {
      textRects: [],
    };
  }

  componentDidMount() {
    this.updateTextRects();
  }

  updateTextRects() {
    const containerElement = this.containerRef.current;
    const filterByTextElement = this.filterByText.current;
    if (containerElement == null || filterByTextElement == null) {
      return;
    }

    const rect = containerElement.getBoundingClientRect();

    const textRects = getTextRects({
      element: filterByTextElement,
      viewports: [],
      words: new Set(splitEnteredText(ENTERED_TEXT)),
      checkElementAtPoint: false,
    }).map(box => ({
      ...box,
      x: box.x - rect.left,
      y: box.y - rect.top,
    }));

    this.setState({ textRects });
  }

  render() {
    const { chars, css, peek } = this.props;
    const { textRects } = this.state;

    let hintZIndex = MAX_Z_INDEX;
    const hint = ({
      left,
      top,
      matchedChars = "",
      chars: unmatchedChars,
      highlighted = false,
      hidden = false,
    }: {|
      /* eslint-disable react/require-default-props */
      left: number,
      top: number,
      matchedChars?: string,
      chars: string,
      highlighted?: boolean,
      hidden?: boolean,
      /* eslint-enable react/require-default-props */
    |}) => {
      hintZIndex--;
      return (

          {matchedChars.length > 0 && (
            {matchedChars}
          )}
          {unmatchedChars}

      );
    };

    return (

          {FILTER_BY_TEXT}

          <Shadow>

              {hint({
                left: 0,
                top: HINT_Y * (HINT_VARIATIONS.length + 1),
                chars: SHRUGGIE,
              })}

              {hint({
                left: HINT_X * 2,
                top: HINT_Y * (HINT_VARIATIONS.length + 1),
                chars: "hidden",
                hidden: true,
              })}

                {ENTERED_TEXT}

              {chars.split("").map((char, index) =>
                hint({
                  left: HINT_X * index,
                  top: 0,
                  chars: char,
                })
              )}

              {HINT_VARIATIONS.map((variations, y) =>
                []
                  .concat(
                    ...variations.map(([numMatched, numChars]) =>
                      [false, true].map(highlighted => ({
                        matchedChars: chars.slice(0, numMatched),
                        chars: chars.slice(numMatched, numMatched + numChars),
                        highlighted,
                      }))
                    )
                  )
                  .map((props, x) =>
                    hint({
                      left: HINT_X * 2 * x,
                      top: HINT_Y * (y + 1),
                      ...props,
                    })
                  )
              )}

              {textRects.map((box, index) => (

              ))}

          </Shadow>

    );
  }
}
<|endoftext|>


<commit_before>'use strict';

function GeoCoordinates(lat, lon){
    if (lat < -90 || lat > 90) {
        throw new RangeError('latitude out of range: -90 <= latitude <= 90');
    }
    if (lon <= -180 || lon > 180) {
        throw new RangeError('latitude out of range: -180 < latitude <= 180');
    }
    Object.defineProperty(this, 'latitude', {value: lat});
    Object.defineProperty(this, 'longitude', {value: lon});
}

GeoCoordinates.create = function(lat, lon){
  return new GeoCoordinates(lat, lon);
};
GeoCoordinates.parse = function(address) {
    var match, latitude, longitude;
    if (match = address.match(/(\d+)([NS])[,\.]?\s*(\d+)([EW])/i)) {
        latitude = /N/i.test(match[2]) ? parseFloat(match[1]) : - parseFloat(match[1]);
        longitude = /E/i.test(match[4]) ? parseFloat(match[3]) : - parseFloat(match[3]);
        return {latitude: latitude, longitude: longitude};
    } else if (match = address.match(/(\d+)([EW])[,\.]?\s*(\d+)([NS])/i)) {
        latitude = /N/i.test(match[4]) ? parseFloat(match[3]) : - parseFloat(match[3]);
        longitude = /E/i.test(match[2]) ? parseFloat(match[1]) : - parseFloat(match[1]);
        return {latitude: latitude, longitude: longitude};
    } else if (match = address.match(/(-?\d+), (-?\d+)/)) {
        latitude = parseFloat(match[1]);
        longitude = parseFloat(match[2]);
        return {latitude: latitude, longitude: longitude};
    } else {
        return null;
    }
};

module.exports = GeoCoordinates;
<commit_msg>spiked methods<commit_after>'use strict';

function GeoCoordinates(lat, lon){
    if (lat < -90 || lat > 90) {
        throw new RangeError('latitude out of range: -90 <= latitude <= 90');
    }
    if (lon <= -180 || lon > 180) {
        throw new RangeError('latitude out of range: -180 < latitude <= 180');
    }
    Object.defineProperty(this, 'latitude', {value: lat});
    Object.defineProperty(this, 'longitude', {value: lon});
}

GeoCoordinates.prototype.toString = function(){
    // TODO test
    var north = this.latitude > 0;
    var east = this.longitude > 0;
    var latitude = north ? '' + this.latitude + 'N' : '' + (-1 * this.latitude) + 'S';
    var longitude = east ? '' + this.longitude + 'E' : '' + (-1 * this.longitude) + 'W';
    return latitude + ', ' + longitude;
};

GeoCoordinates.prototype.round = function(dp){
    // TODO test
    var r = require('round-decimal/decimal-places')(dp);
    return GeoCoordinates.create(r(this.latitude), r(this.longitude));
}

GeoCoordinates.create = function(lat, lon){
    return new GeoCoordinates(lat, lon);
};

GeoCoordinates.from_place = function(place) {
    // TODO test
    return new GeoCoordinates(place.latitude, place.longitude);
};

GeoCoordinates.parse = function(address) {
    var match, latitude, longitude;
    if (match = address.match(/(\d+)([NS])[,\.]?\s*(\d+)([EW])/i)) {
        latitude = /N/i.test(match[2]) ? parseFloat(match[1]) : - parseFloat(match[1]);
        longitude = /E/i.test(match[4]) ? parseFloat(match[3]) : - parseFloat(match[3]);
        return {latitude: latitude, longitude: longitude};
    } else if (match = address.match(/(\d+)([EW])[,\.]?\s*(\d+)([NS])/i)) {
        latitude = /N/i.test(match[4]) ? parseFloat(match[3]) : - parseFloat(match[3]);
        longitude = /E/i.test(match[2]) ? parseFloat(match[1]) : - parseFloat(match[1]);
        return {latitude: latitude, longitude: longitude};
    } else if (match = address.match(/(-?\d+), (-?\d+)/)) {
        latitude = parseFloat(match[1]);
        longitude = parseFloat(match[2]);
        return {latitude: latitude, longitude: longitude};
    } else {
        return null;
    }
};

module.exports = GeoCoordinates;
<|endoftext|>


<commit_before>var React = require('react');
var MessageTile = require('../molecules/MessageTile');
var RoomHeader = require('../molecules/RoomHeader');
var MessageComposer = require('../molecules/MessageComposer');

var MatrixClientPeg = require("../MatrixClientPeg");

module.exports = React.createClass({
    getInitialState: function() {
        return {
            room: MatrixClientPeg.get().getRoom(this.props.roomId)
        }
    },

    componentWillMount: function() {
        MatrixClientPeg.get().on("Room.timeline", this.onRoomTimeline);
    },

    componentWillUnmount: function() {
        MatrixClientPeg.get().removeListener("Room.timeline", this.onRoomTimeline);
    },

    componentWillReceiveProps: function(props) {
        this.setState({
            room: MatrixClientPeg.get().getRoom(props.roomId)
        });
    },

    onRoomTimeline: function(ev, room, toStartOfTimeline) {
        if (room.roomId != this.props.roomId) return;
        this.setState({
            room: MatrixClientPeg.get().getRoom(this.props.roomId)
        });
    },

    getMessageTiles: function() {
        return this.state.room.timeline.map(function(mxEv) {
            return (

<MessageTile mxEvent={mxEv} key={mxEv.getId()} />

            );
        });
    },

    render: function() {
        return (

                <RoomHeader room={this.state.room} />

                    {this.getMessageTiles()}

                <MessageComposer roomId={this.props.roomId} />

        );
    },
});

<commit_msg>Oops, put key in the right place<commit_after>var React = require('react');
var MessageTile = require('../molecules/MessageTile');
var RoomHeader = require('../molecules/RoomHeader');
var MessageComposer = require('../molecules/MessageComposer');

var MatrixClientPeg = require("../MatrixClientPeg");

module.exports = React.createClass({
    getInitialState: function() {
        return {
            room: MatrixClientPeg.get().getRoom(this.props.roomId)
        }
    },

    componentWillMount: function() {
        MatrixClientPeg.get().on("Room.timeline", this.onRoomTimeline);
    },

    componentWillUnmount: function() {
        MatrixClientPeg.get().removeListener("Room.timeline", this.onRoomTimeline);
    },

    componentWillReceiveProps: function(props) {
        this.setState({
            room: MatrixClientPeg.get().getRoom(props.roomId)
        });
    },

    onRoomTimeline: function(ev, room, toStartOfTimeline) {
        if (room.roomId != this.props.roomId) return;
        this.setState({
            room: MatrixClientPeg.get().getRoom(this.props.roomId)
        });
    },

    getMessageTiles: function() {
        return this.state.room.timeline.map(function(mxEv) {
            return (

<MessageTile mxEvent={mxEv} />

            );
        });
    },

    render: function() {
        return (

                <RoomHeader room={this.state.room} />

                    {this.getMessageTiles()}

                <MessageComposer roomId={this.props.roomId} />

        );
    },
});

<|endoftext|>


<commit_before>import React from 'react';
import DocumentTitle from 'react-document-title';

import { prefixLink } from 'gatsby-helpers';

const BUILD_TIME = new Date().getTime();

module.exports = React.createClass({
  propTypes () {
    return {
      title: React.PropTypes.string,
    }
  },
  render () {
    const title = DocumentTitle.rewind();

    let css;
    if (process.env.NODE_ENV === 'production') {
      css = <link rel="stylesheet" href={prefixLink(`/styles.css?t=${BUILD_TIME}`)} />
    }

    return (

          <meta charSet="utf-8" />
          <meta httpEquiv="X-UA-Compatible" content="IE=edge" />
          <meta
            name="viewport"
            content="width=device-width, initial-scale=1.0 maximum-scale=1.0"
          />
          <title>{title}</title>
          <meta name="description"
                content="Investigations des sols, gaz du sol et eaux souterrainnes dans des zones à accès difficile." />
          <meta property="og:title" content={title} />
          <meta property="og:type" content="website" />

          <link rel="shortcut icon" href={this.props.favicon} />
          <link href='https://fonts.googleapis.com/css?family=Open+Sans:300italic,400italic,600italic,700italic,800italic,400,300,600,700,800' rel='stylesheet' type='text/css' />
          <link href='https://fonts.googleapis.com/css?family=Merriweather:400,300,300italic,400italic,700,700italic,900,900italic' rel='stylesheet' type='text/css' />
          <link href='https://maxcdn.bootstrapcdn.com/font-awesome/4.6.3/css/font-awesome.min.css' rel='stylesheet' type='text/css' />
          {css}


<commit_before>/* jshint node:true */
/**
 * PUSH Notification server
 * (c) Telefonica Digital, 2012 - All rights reserved
 * License: GNU Affero V3 (see LICENSE file)
 * Fernando Rodríguez Sela <frsela@tid.es>
 * Guillermo Lopez Leal <gll@tid.es>
 */

'use strict';

var Log = require('../common/Logger.js'),
    MsgBroker = require('../common/MsgBroker.js'),
    DataStore = require('../common/DataStore.js'),
    config = require('../config.js').NS_Monitor,
    connectionstate = require('../common/constants.js').connectionstate;

function NS_Monitor() {
    this.closingCorrectly = false;
    this.dataStoreReady = false;
    this.msgBrokerReady = false;
    this.readyTimeout = undefined;
    this.readyUDPTimeout = undefined;
    this.retryUDPnotACKedInterval = undefined;
}

NS_Monitor.prototype.checkReady = function() {
    if (this.dataStoreReady && this.msgBrokerReady) {
        Log.debug('NS_Monitor::checkReady --> We are ready. Clearing any readyTimeout');
        clearTimeout(this.readyTimeout);
    } else {
        Log.debug('NS_Monitor::checkReady --> Not ready yet. dataStoreReady=' + this.dataStoreReady +
            ', msgBrokerReady=' + this.msgBrokerReady);
    }
    return this.dataStoreReady && this.msgBrokerReady;
};

NS_Monitor.prototype.start = function() {
    Log.info('NS_Monitor::start --> server starting');
    var self = this;

    MsgBroker.once('ready', function() {
        Log.info('NS_Monitor::start --> MsgBroker ready and connected');
        self.msgBrokerReady = true;
        self.checkReady();
    });

    MsgBroker.on('ready', this.subscribeQueues.bind(this));

    MsgBroker.once('closed', function() {
        self.msgBrokerReady = false;
        if (self.closingCorrectly) {
            Log.info('NS_AS::stop --> Closed MsgBroker');
            return;
        }
        Log.critical(Log.messages.CRITICAL_MBDISCONNECTED, {
            'class': 'NS_Monitor',
            'method': 'start'
        });
        self.stop();
    });

    DataStore.on('ready', function() {
        Log.info('NS_Monitor::start --> DataStore ready and connected');
        self.dataStoreReady = true;
        self.checkReady();
    });

    DataStore.on('closed', function() {
        if (self.closingCorrectly) {
            Log.info('NS_Monitor::start --> Closed DataStore');
            return;
        }
        Log.critical(Log.messages.CRITICAL_DBDISCONNECTED, {
            'class': 'NS_Monitor',
            'method': 'start'
        });
        self.dataStoreReady = false;
        self.stop();
    });

    //Hack. Once we have a disconnected queue, we must subscribe again for each
    //broker.
    //This happens on RabbitMQ as follows:
    // 1) We are connected to several brokers
    // 2) We are subscribed to the same queue on those brokers
    // 3) Master fails :(
    // 4) RabbitMQ promotes the eldest slave to be the master
    // 5) RabbitMQ disconnects all clients. Not a socket disconnection, but
    //    unbinds the connection to the subscribed queue.
    //
    // Hacky solution: once we have a disconnected queue (a socket error), we
    // subscribe again to the queue.
    // It's not beautiful (we should really unsubscribe all queues first), but works.
    // This *MIGHT* require OPS job if we have a long-long socket errors with queues.
    // (we might end up with gazillions (hundreds, really) callbacks on the same
    // socket for handling messages)
    MsgBroker.on('queuedisconnected', MsgBroker.reconnectQueues);

    // Connect to the message broker
    process.nextTick(function() {
        MsgBroker.start();
        DataStore.start();
    });

    //Check if we are alive
    this.readyTimeout = setTimeout(function() {
        Log.debug('NS_Monitor --> readyTimeout fired');
        if (!self.checkReady()) {
            Log.critical(Log.messages.CRITICAL_NOTREADY);
        }
    }, 30 * 1000); //Wait 30 seconds

    // Retry UDP messages for unACKed messages
    this.readyUDPTimeout = setTimeout(function() {
        self.retryUDPnotACKedInterval = setInterval(function retryUDPnotACKed() {
            self.retryUDPnotACKed();
        }, 31 * 1000); // Wait to be ready (31 seconds)
    }, config.retryTime);
};

NS_Monitor.prototype.stop = function(correctly) {
    this.closingCorrectly = correctly;
    Log.info('NS_Monitor::stop --> Closing NS_Monitor server');
    clearInterval(this.retryUDPnotACKedInterval);
    clearTimeout(this.readyTimeout);
    clearTimeout(this.readyUDPTimeout);

    //Closing connection with MsgBroker and DataStore
    MsgBroker.removeAllListeners();
    DataStore.removeAllListeners();
    MsgBroker.stop();
    DataStore.stop();
    setTimeout(function() {
        process.exit(0);
    }, 5000);
};

NS_Monitor.prototype.retryUDPnotACKed = function() {
    var self = this;
    Log.debug('NS_Monitor::retryUDPnotACKed --> Starting retry procedure');
    DataStore.getUDPClientsAndUnACKedMessages(function(error, nodes) {
        if (error) {
            return;
        }

        if (!Array.isArray(nodes) || !nodes.length) {
            Log.debug('NS_Monitor::retryUDPnotACKed --> No pending messages for UDP clients');
            return;
        }

        nodes.forEach(function(node) {
            self.onNodeData(node, {});
        });
    });
};

NS_Monitor.prototype.onNodeData = function(nodeData, notif) {
    if (!nodeData || !nodeData.si || !nodeData._id || !nodeData.dt) {
        Log.error(Log.messages.ERROR_BACKENDERROR, {
            'class': 'NS_Monitor',
            'method': 'onNodeData',
            'extra': 'No enough info'
        });
        return;
    }

    // Is the node connected? AKA: is websocket?
    if (nodeData.co === connectionstate.DISCONNECTED) {
        Log.debug(
            'NS_Monitor::onNodeData --> Node recovered but not connected, just delaying'
        );
        return;
    }
    Log.debug('NS_Monitor::onNodeData --> Node connected:', nodeData);

    Log.notify(Log.messages.NOTIFY_INCOMING_TO, {
        uaid: nodeData._id,
        appToken: notif.app,
        version: notif.vs,
        mcc: (nodeData.dt.mobilenetwork && nodeData.dt.mobilenetwork.mcc) || 0,
        mnc: (nodeData.dt.mobilenetwork && nodeData.dt.mobilenetwork.mnc) || 0
    });
    var body = {
        uaid: nodeData._id,
        dt: nodeData.dt,
        notif: notif
    };
    MsgBroker.push(nodeData.si, body);
};

NS_Monitor.prototype.subscribeQueues = function(broker) {
    //We want a durable queue, that do not autodeletes on last closed connection, and
    // with HA activated (mirrored in each rabbit server)
    var args = {
        durable: true,
        autoDelete: false
    };
    MsgBroker.subscribe(
        'newMessages',
        args,
        broker,
        this.newMessage.bind(this)
    );
};

NS_Monitor.prototype.newMessage = function(msg) {
    Log.debug('NS_Monitor::newMessage --> Message received --', msg);
    if (!msg.app || !msg.ch || !msg.vs || !msg.no) {
        Log.error('NS_Monitor::newMessage --> Not enough data', msg);
        return;
    }
    DataStore.getNodeData(msg.no, (function(error, data) {
        this.onNodeData(data, msg);
    }).bind(this));
};

exports.NS_Monitor = NS_Monitor;
<commit_msg>Issue 315 - [Monitor] Show notify traces of received messages for all devices<commit_after>/* jshint node:true */
/**
 * PUSH Notification server
 * (c) Telefonica Digital, 2012 - All rights reserved
 * License: GNU Affero V3 (see LICENSE file)
 * Fernando Rodríguez Sela <frsela@tid.es>
 * Guillermo Lopez Leal <gll@tid.es>
 */

'use strict';

var Log = require('../common/Logger.js'),
    MsgBroker = require('../common/MsgBroker.js'),
    DataStore = require('../common/DataStore.js'),
    config = require('../config.js').NS_Monitor,
    connectionstate = require('../common/constants.js').connectionstate;

function NS_Monitor() {
    this.closingCorrectly = false;
    this.dataStoreReady = false;
    this.msgBrokerReady = false;
    this.readyTimeout = undefined;
    this.readyUDPTimeout = undefined;
    this.retryUDPnotACKedInterval = undefined;
}

NS_Monitor.prototype.checkReady = function() {
    if (this.dataStoreReady && this.msgBrokerReady) {
        Log.debug('NS_Monitor::checkReady --> We are ready. Clearing any readyTimeout');
        clearTimeout(this.readyTimeout);
    } else {
        Log.debug('NS_Monitor::checkReady --> Not ready yet. dataStoreReady=' + this.dataStoreReady +
            ', msgBrokerReady=' + this.msgBrokerReady);
    }
    return this.dataStoreReady && this.msgBrokerReady;
};

NS_Monitor.prototype.start = function() {
    Log.info('NS_Monitor::start --> server starting');
    var self = this;

    MsgBroker.once('ready', function() {
        Log.info('NS_Monitor::start --> MsgBroker ready and connected');
        self.msgBrokerReady = true;
        self.checkReady();
    });

    MsgBroker.on('ready', this.subscribeQueues.bind(this));

    MsgBroker.once('closed', function() {
        self.msgBrokerReady = false;
        if (self.closingCorrectly) {
            Log.info('NS_AS::stop --> Closed MsgBroker');
            return;
        }
        Log.critical(Log.messages.CRITICAL_MBDISCONNECTED, {
            'class': 'NS_Monitor',
            'method': 'start'
        });
        self.stop();
    });

    DataStore.on('ready', function() {
        Log.info('NS_Monitor::start --> DataStore ready and connected');
        self.dataStoreReady = true;
        self.checkReady();
    });

    DataStore.on('closed', function() {
        if (self.closingCorrectly) {
            Log.info('NS_Monitor::start --> Closed DataStore');
            return;
        }
        Log.critical(Log.messages.CRITICAL_DBDISCONNECTED, {
            'class': 'NS_Monitor',
            'method': 'start'
        });
        self.dataStoreReady = false;
        self.stop();
    });

    //Hack. Once we have a disconnected queue, we must subscribe again for each
    //broker.
    //This happens on RabbitMQ as follows:
    // 1) We are connected to several brokers
    // 2) We are subscribed to the same queue on those brokers
    // 3) Master fails :(
    // 4) RabbitMQ promotes the eldest slave to be the master
    // 5) RabbitMQ disconnects all clients. Not a socket disconnection, but
    //    unbinds the connection to the subscribed queue.
    //
    // Hacky solution: once we have a disconnected queue (a socket error), we
    // subscribe again to the queue.
    // It's not beautiful (we should really unsubscribe all queues first), but works.
    // This *MIGHT* require OPS job if we have a long-long socket errors with queues.
    // (we might end up with gazillions (hundreds, really) callbacks on the same
    // socket for handling messages)
    MsgBroker.on('queuedisconnected', MsgBroker.reconnectQueues);

    // Connect to the message broker
    process.nextTick(function() {
        MsgBroker.start();
        DataStore.start();
    });

    //Check if we are alive
    this.readyTimeout = setTimeout(function() {
        Log.debug('NS_Monitor --> readyTimeout fired');
        if (!self.checkReady()) {
            Log.critical(Log.messages.CRITICAL_NOTREADY);
        }
    }, 30 * 1000); //Wait 30 seconds

    // Retry UDP messages for unACKed messages
    this.readyUDPTimeout = setTimeout(function() {
        self.retryUDPnotACKedInterval = setInterval(function retryUDPnotACKed() {
            self.retryUDPnotACKed();
        }, 31 * 1000); // Wait to be ready (31 seconds)
    }, config.retryTime);
};

NS_Monitor.prototype.stop = function(correctly) {
    this.closingCorrectly = correctly;
    Log.info('NS_Monitor::stop --> Closing NS_Monitor server');
    clearInterval(this.retryUDPnotACKedInterval);
    clearTimeout(this.readyTimeout);
    clearTimeout(this.readyUDPTimeout);

    //Closing connection with MsgBroker and DataStore
    MsgBroker.removeAllListeners();
    DataStore.removeAllListeners();
    MsgBroker.stop();
    DataStore.stop();
    setTimeout(function() {
        process.exit(0);
    }, 5000);
};

NS_Monitor.prototype.retryUDPnotACKed = function() {
    var self = this;
    Log.debug('NS_Monitor::retryUDPnotACKed --> Starting retry procedure');
    DataStore.getUDPClientsAndUnACKedMessages(function(error, nodes) {
        if (error) {
            return;
        }

        if (!Array.isArray(nodes) || !nodes.length) {
            Log.debug('NS_Monitor::retryUDPnotACKed --> No pending messages for UDP clients');
            return;
        }

        nodes.forEach(function(node) {
            self.onNodeData(node, {});
        });
    });
};

NS_Monitor.prototype.onNodeData = function(nodeData, notif) {
    if (!nodeData || !nodeData.si || !nodeData._id || !nodeData.dt) {
        Log.error(Log.messages.ERROR_BACKENDERROR, {
            'class': 'NS_Monitor',
            'method': 'onNodeData',
            'extra': 'No enough info'
        });
        return;
    }

    Log.notify(Log.messages.NOTIFY_INCOMING_TO, {
        uaid: nodeData._id,
        appToken: notif.app,
        version: notif.vs,
        mcc: (nodeData.dt.mobilenetwork && nodeData.dt.mobilenetwork.mcc) || 0,
        mnc: (nodeData.dt.mobilenetwork && nodeData.dt.mobilenetwork.mnc) || 0
    });

    // Is the node connected? AKA: is websocket?
    if (nodeData.co === connectionstate.DISCONNECTED) {
        Log.debug(
            'NS_Monitor::onNodeData --> Node recovered but not connected, just delaying'
        );
        return;
    }
    Log.debug('NS_Monitor::onNodeData --> Node connected:', nodeData);

    var body = {
        uaid: nodeData._id,
        dt: nodeData.dt,
        notif: notif
    };
    MsgBroker.push(nodeData.si, body);
};

NS_Monitor.prototype.subscribeQueues = function(broker) {
    //We want a durable queue, that do not autodeletes on last closed connection, and
    // with HA activated (mirrored in each rabbit server)
    var args = {
        durable: true,
        autoDelete: false
    };
    MsgBroker.subscribe(
        'newMessages',
        args,
        broker,
        this.newMessage.bind(this)
    );
};

NS_Monitor.prototype.newMessage = function(msg) {
    Log.debug('NS_Monitor::newMessage --> Message received --', msg);
    if (!msg.app || !msg.ch || !msg.vs || !msg.no) {
        Log.error('NS_Monitor::newMessage --> Not enough data', msg);
        return;
    }
    DataStore.getNodeData(msg.no, (function(error, data) {
        this.onNodeData(data, msg);
    }).bind(this));
};

exports.NS_Monitor = NS_Monitor;
<|endoftext|>


<commit_before>/**
 * PUSH Notification server V 0.3
 * (c) Telefonica Digital, 2012 - All rights reserver
 * Fernando Rodríguez Sela <frsela@tid.es>
 * Guillermo Lopez Leal <gll@tid.es>
 */

// TODO: Error methods
// TODO: push_url_recover_method
// TODO: verify origin
// TODO: URL Parser based on regexp
// TODO: Replies to the 3rd. party server

var log = require("../common/logger.js").getLogger;
var WebSocketServer = require('websocket').server;
var http = require('http');
var crypto = require("../common/cryptography.js").getCrypto;
var dataManager = require("./datamanager.js");
var Connectors = require("./connectors/connector_base.js").getConnectorFactory();
var token = require("../common/token.js").getToken;

function server(ip, port) {
  this.ip = ip;
  this.port = port;
}

server.prototype = {
  //////////////////////////////////////////////
  // Constructor
  //////////////////////////////////////////////

  init: function() {
    // Create a new HTTP Server
    this.server = http.createServer(this.onHTTPMessage.bind(this));
    this.server.listen(this.port, this.ip);
    log.info('HTTP push UA_WS server running on ' + this.ip + ":" + this.port);

    // Websocket init
    this.wsServer = new WebSocketServer({
      httpServer: this.server,
      keepalive: require('../config.js').NS_UA_WS.websocket_params.keepalive,
      keepaliveInterval: require('../config.js').NS_UA_WS.websocket_params.keepaliveInterval,
      dropConnectionOnKeepaliveTimeout: require('../config.js').NS_UA_WS.websocket_params.dropConnectionOnKeepaliveTimeout,
      keepaliveGracePeriod: require('../config.js').NS_UA_WS.websocket_params.keepaliveGracePeriod,

      // You should not use autoAcceptConnections for production
      // applications, as it defeats all standard cross-origin protection
      // facilities built into the protocol and the browser.  You should
      // *always* verify the connection's origin and decide whether or not
      // to accept it.
      autoAcceptConnections: false
    });

    this.wsServer.on('request', this.onWSRequest);
  },

  //////////////////////////////////////////////
  // HTTP callbacks
  //////////////////////////////////////////////
  onHTTPMessage: function(request, response) {
    log.debug((new Date()) + 'HTTP: Received request for ' + request.url);
    var url = this.parseURL(request.url);
    this.status = "";
    this.text = "";
    //response.writeHead(200, {"Content-Type": "text/plain", "access-control-allow-origin": "*"} );
    log.debug("HTTP: Parsed URL: " + JSON.stringify(url));
    switch(url.command) {
      case "token":
        this.text += token.get();
        this.status = 200;
        break;

      case "register":
        // We only accept application registration under the HTTP interface
        if(url.token != "app") {
          log.debug("HTTP: Only application registration under this interface");
          this.status = 404;
          break;
        }
        log.debug("HTTP: Application registration message");
        var appToken = crypto.hashSHA256(url.parsedURL.query.a);
        dataManager.getDataManager().registerApplication(appToken,url.parsedURL.query.n);
        this.status = 200;
        var baseURL = require('../config.js').NS_AS.publicBaseURL;
        this.text += (baseURL + "/notify/" + appToken);
        break;

      default:
        log.debug("HTTP: Command not recognized");
        this.status = 404;
    }

    // Close connection
    response.statusCode = this.status;
    response.setHeader("Content-Type", "text/plain");
    response.setHeader("access-control-allow-origin", "*");
    response.write(this.text);
    response.end();
  },

  //////////////////////////////////////////////
  // WebSocket callbacks
  //////////////////////////////////////////////
  onWSRequest: function(request) {
    ///////////////////////
    // WS Callbacks
    ///////////////////////
    this.onWSMessage = function(message) {
      if (message.type === 'utf8') {
        console.log('WS: Received Message: ' + message.utf8Data);
        try {
          var query = JSON.parse(message.utf8Data);
        } catch(e) {
          console.log("WS: Data received is not a valid JSON package");
          connection.sendUTF('{ "error": "Data received is not a valid JSON package" }');
          connection.close();
          return;
        }

        switch(query.command) {
        case "register/node":
          console.log("WS: Node registration message");
          // Token verification
          if(!token.verify(query.data.token)) {
            console.log("WS: Token not valid (Checksum failed)");
            connection.sendUTF('{ "error": "Token received is not accepted. Please get a valid one" }');
            connection.close();
            return;
          }
          var c = Connectors.getConnector(query.data, connection);
          dataManager.getDataManager().registerNode(query.data.token, c);
          break;

        case "register/app":
          console.log("WS: Application registration message");
          dataManager.getDataManager().registerApplication(query.data.apptoken,query.data.nodetoken);
          var baseURL = require('./config.js').publicBaseURL;
          connection.sendUTF(baseURL + "/notify/" + query.data.apptoken);
          break;

        default:
          console.log("WS: Command not recognized");
          connection.sendUTF('{ "error": "Command not recognized" }');
          connection.close();
        }
      } else if (message.type === 'binary') {
        // No binary data supported yet
        console.log('WS: Received Binary Message of ' + message.binaryData.length + ' bytes');
        connection.sendUTF('{ "error": "Binary messages not yet supoprted" }');
        connection.close();
      }
    };

    this.onWSClose = function(reasonCode, description) {
      // TODO: De-register this node
      console.log((new Date()) + ' Peer ' + connection.remoteAddress + ' disconnected.');
    }

    /**
     * Verify origin in order to accept or reject connections
     */
    this.originIsAllowed = function(origin) {
      // TODO: put logic here to detect whether the specified origin is allowed.
      return true;
    }

    ///////////////////////
    // Websocket creation
    ///////////////////////
    if (!this.originIsAllowed(request.origin)) {
      // Make sure we only accept requests from an allowed origin
      request.reject();
      console.log((new Date()) + ' Connection from origin ' + request.origin + ' rejected.');
      return;
    }

    var connection = request.accept('push-notification', request.origin);
    console.log((new Date()) + ' Connection accepted.');
    connection.on('message', this.onWSMessage);
    connection.on('close', this.onWSClose);
  },

  ///////////////////////
  // Auxiliar methods
  ///////////////////////
  parseURL: function(url) {
    var urlparser = require('url');
    var data = {};
    data.parsedURL = urlparser.parse(url,true);
    var path = data.parsedURL.pathname.split("/");
    data.command = path[1];
    if(path.length > 2) {
      data.token = path[2];
    } else {
      data.token = data.parsedURL.query.token;
    }
    return data;
  }
};

// Exports
exports.server = server;
<commit_msg>UA-WS log messages using Logger module<commit_after>/**
 * PUSH Notification server V 0.3
 * (c) Telefonica Digital, 2012 - All rights reserver
 * Fernando Rodríguez Sela <frsela@tid.es>
 * Guillermo Lopez Leal <gll@tid.es>
 */

// TODO: Error methods
// TODO: push_url_recover_method
// TODO: verify origin
// TODO: URL Parser based on regexp
// TODO: Replies to the 3rd. party server

var log = require("../common/logger.js").getLogger;
var WebSocketServer = require('websocket').server;
var http = require('http');
var crypto = require("../common/cryptography.js").getCrypto;
var dataManager = require("./datamanager.js");
var Connectors = require("./connectors/connector_base.js").getConnectorFactory();
var token = require("../common/token.js").getToken;

function server(ip, port) {
  this.ip = ip;
  this.port = port;
}

server.prototype = {
  //////////////////////////////////////////////
  // Constructor
  //////////////////////////////////////////////

  init: function() {
    // Create a new HTTP Server
    this.server = http.createServer(this.onHTTPMessage.bind(this));
    this.server.listen(this.port, this.ip);
    log.info('HTTP push UA_WS server running on ' + this.ip + ":" + this.port);

    // Websocket init
    this.wsServer = new WebSocketServer({
      httpServer: this.server,
      keepalive: require('../config.js').NS_UA_WS.websocket_params.keepalive,
      keepaliveInterval: require('../config.js').NS_UA_WS.websocket_params.keepaliveInterval,
      dropConnectionOnKeepaliveTimeout: require('../config.js').NS_UA_WS.websocket_params.dropConnectionOnKeepaliveTimeout,
      keepaliveGracePeriod: require('../config.js').NS_UA_WS.websocket_params.keepaliveGracePeriod,

      // You should not use autoAcceptConnections for production
      // applications, as it defeats all standard cross-origin protection
      // facilities built into the protocol and the browser.  You should
      // *always* verify the connection's origin and decide whether or not
      // to accept it.
      autoAcceptConnections: false
    });

    this.wsServer.on('request', this.onWSRequest);
  },

  //////////////////////////////////////////////
  // HTTP callbacks
  //////////////////////////////////////////////
  onHTTPMessage: function(request, response) {
    log.debug((new Date()) + 'HTTP: Received request for ' + request.url);
    var url = this.parseURL(request.url);
    this.status = "";
    this.text = "";
    //response.writeHead(200, {"Content-Type": "text/plain", "access-control-allow-origin": "*"} );
    log.debug("HTTP: Parsed URL: " + JSON.stringify(url));
    switch(url.command) {
      case "token":
        this.text += token.get();
        this.status = 200;
        break;

      case "register":
        // We only accept application registration under the HTTP interface
        if(url.token != "app") {
          log.debug("HTTP: Only application registration under this interface");
          this.status = 404;
          break;
        }
        log.debug("HTTP: Application registration message");
        var appToken = crypto.hashSHA256(url.parsedURL.query.a);
        dataManager.getDataManager().registerApplication(appToken,url.parsedURL.query.n);
        this.status = 200;
        var baseURL = require('../config.js').NS_AS.publicBaseURL;
        this.text += (baseURL + "/notify/" + appToken);
        break;

      default:
        log.debug("HTTP: Command not recognized");
        this.status = 404;
    }

    // Close connection
    response.statusCode = this.status;
    response.setHeader("Content-Type", "text/plain");
    response.setHeader("access-control-allow-origin", "*");
    response.write(this.text);
    response.end();
  },

  //////////////////////////////////////////////
  // WebSocket callbacks
  //////////////////////////////////////////////
  onWSRequest: function(request) {
    ///////////////////////
    // WS Callbacks
    ///////////////////////
    this.onWSMessage = function(message) {
      if (message.type === 'utf8') {
        log.debug('WS: Received Message: ' + message.utf8Data);
        try {
          var query = JSON.parse(message.utf8Data);
        } catch(e) {
          log.debug("WS: Data received is not a valid JSON package");
          connection.sendUTF('{ "error": "Data received is not a valid JSON package" }');
          connection.close();
          return;
        }

        switch(query.command) {
        case "register/node":
          log.debug("WS: Node registration message");
          // Token verification
          if(!token.verify(query.data.token)) {
            log.debug("WS: Token not valid (Checksum failed)");
            connection.sendUTF('{ "error": "Token received is not accepted. Please get a valid one" }');
            connection.close();
            return;
          }
          var c = Connectors.getConnector(query.data, connection);
          dataManager.getDataManager().registerNode(query.data.token, c);
          break;

        case "register/app":
          log.debug("WS: Application registration message");
          dataManager.getDataManager().registerApplication(query.data.apptoken,query.data.nodetoken);
          var baseURL = require('./config.js').publicBaseURL;
          connection.sendUTF(baseURL + "/notify/" + query.data.apptoken);
          break;

        default:
          log.debug("WS: Command not recognized");
          connection.sendUTF('{ "error": "Command not recognized" }');
          connection.close();
        }
      } else if (message.type === 'binary') {
        // No binary data supported yet
        log.debug('WS: Received Binary Message of ' + message.binaryData.length + ' bytes');
        connection.sendUTF('{ "error": "Binary messages not yet supoprted" }');
        connection.close();
      }
    };

    this.onWSClose = function(reasonCode, description) {
      // TODO: De-register this node
      log.debug(' Peer ' + connection.remoteAddress + ' disconnected.');
    }

    /**
     * Verify origin in order to accept or reject connections
     */
    this.originIsAllowed = function(origin) {
      // TODO: put logic here to detect whether the specified origin is allowed.
      return true;
    }

    ///////////////////////
    // Websocket creation
    ///////////////////////
    if (!this.originIsAllowed(request.origin)) {
      // Make sure we only accept requests from an allowed origin
      request.reject();
      log.debug(' Connection from origin ' + request.origin + ' rejected.');
      return;
    }

    var connection = request.accept('push-notification', request.origin);
    log.debug(' Connection accepted.');
    connection.on('message', this.onWSMessage);
    connection.on('close', this.onWSClose);
  },

  ///////////////////////
  // Auxiliar methods
  ///////////////////////
  parseURL: function(url) {
    var urlparser = require('url');
    var data = {};
    data.parsedURL = urlparser.parse(url,true);
    var path = data.parsedURL.pathname.split("/");
    data.command = path[1];
    if(path.length > 2) {
      data.token = path[2];
    } else {
      data.token = data.parsedURL.query.token;
    }
    return data;
  }
};

// Exports
exports.server = server;
<|endoftext|>


<commit_before>var enemiesArray = ["enemy_1", "enemy_2", "enemy_3", "enemy_4", "enemy_5", "enemy_6", "enemy_7"];

class Enemies {

  constructor(game, nr){
    this.game = game;
    this.nr = nr
    this.all = game.add.group();
  };

  init() {
    this.createMany();
    this.align();
    this.animate();
  };

  createMany(group, nr) {
    group = group || this.all;
    nr = nr || this.nr;

    group.enableBody = true;
    for (var i = 0; i < nr; i++)
    {
      group.create(i*10, 0, 'enemy_1');
    }
  };

  align(group) {
    group = group || this.all;
    var index = -1;
    for(var y = 0; y < 4; y++) {
      for(var x = 0; x < 10; x++) {
        var child = group.getAt(index += 1)
        child.reset(x*60, y*50)
        child.anchor.setTo(0.5, 0.5);
      }
    }
  };

  animate() {
    this.all.x = 100;
    this.all.y = 50;

    var tween = this.game.add.tween(this.all).to( {x:150}, 2000, Phaser.Easing.Linear.None, true, 0, 1000, true);
    tween.onStart.add(descend, this);

    function descend() {
      this.game.add.tween(this.all).to( {y:250}, 10000, Phaser.Easing.Linear.None, true, 0, 1000, true);
    }
  };

  update(level, group) {
    group = group || this.all;
    group.forEach(function(enemy) {
      enemy.revive();
      enemy.loadTexture(enemiesArray[level -1], 0);
    }, this);
  }
};

export default Enemies;
<commit_msg>incorporated newly discovered changes to #animate on master branch<commit_after>var enemiesArray = ["enemy_1", "enemy_2", "enemy_3", "enemy_4", "enemy_5", "enemy_6", "enemy_7"];

class Enemies {

  constructor(game, nr){
    this.game = game;
    this.nr = nr
    this.all = game.add.group();
  };

  init() {
    this.createMany();
    this.align();
    this.animate();
  };

  createMany(group, nr) {
    group = group || this.all;
    nr = nr || this.nr;

    group.enableBody = true;
    for (var i = 0; i < nr; i++)
    {
      group.create(i*10, 0, 'enemy_1');
    }
  };

  align(group) {
    group = group || this.all;
    var index = -1;
    for(var y = 0; y < 4; y++) {
      for(var x = 0; x < 10; x++) {
        var child = group.getAt(index += 1)
        child.reset(x*60, y*50)
        child.anchor.setTo(0.5, 0.5);
      }
    }
  };

  animate() {
    this.all.x = 100;
    this.all.y = 50;

    var tween;

    this.all.forEach(function (enemy, i) {
      tween = this.game.add.tween(enemy).to( { y: enemy.body.y + 5 }, 500, Phaser.Easing.Sinusoidal.InOut, true, this.game.rnd.integerInRange(0, 500), 1000, true);
      tween = this.game.add.tween(this.all).to( { x: 150 }, 2000, Phaser.Easing.Linear.None, true, 0, 1000, true);
    }, this);
    tween.onStart.add(descend, this);

    function descend() {
      this.game.add.tween(this.all).to( { y: this.all.y + 10 }, 2500, Phaser.Easing.Linear.None, true, 0, 0, false);
    }

    // this.all.x = 100;
    // this.all.y = 50;
    //
    // var tween = this.game.add.tween(this.all).to( {x:150}, 2000, Phaser.Easing.Linear.None, true, 0, 1000, true);
    // tween.onStart.add(descend, this);
    //
    // function descend() {
    //   this.game.add.tween(this.all).to( {y:250}, 10000, Phaser.Easing.Linear.None, true, 0, 1000, true);
    // }
  };

  update(level, group) {
    group = group || this.all;
    group.forEach(function(enemy) {
      enemy.revive();
      enemy.loadTexture(enemiesArray[level -1], 0);
    }, this);
  }
};

export default Enemies;
<|endoftext|>


<commit_before>goog.provide('ol.control.Zoom');

goog.require('ol.control.Control');

goog.require('goog.dom');

/**
 * @constructor
 * @extends {ol.control.Control}
 * @param {boolean|undefined} opt_autoActivate
 */
ol.control.Zoom = function(opt_autoActivate) {

    goog.base(this, opt_autoActivate);

    /**
     * @type {Node}
     */
    this.inButton_ = null;

    /**
     * @type {Node}
     */
    this.outButton_ = null;

    /**
     * Activate this control when it is added to a map.  Default is true.
     *
     * @type {boolean}
     */
    this.autoActivate_ =
        goog.isDef(opt_autoActivate) ? opt_autoActivate : true;

};
goog.inherits(ol.control.Zoom, ol.control.Control);

/**
 * @param {ol.Map} map
 */
ol.control.Zoom.prototype.setMap = function(map) {
    var container = goog.dom.createDom('div', ol.control.Zoom.RES.CLS);
    this.inButton_ = goog.dom.createDom(
        'div', ol.control.Zoom.RES.IN_CLS,
        goog.dom.createDom('a', {'href': '#zoomIn'})
    );
    goog.dom.setTextContent(
        /** @type {Element} */ (this.inButton_.firstChild),
        ol.control.Zoom.RES.IN_TEXT
    );
    this.outButton_ = goog.dom.createDom(
        'div', ol.control.Zoom.RES.OUT_CLS,
        goog.dom.createDom('a', {'href': '#zoomOut'})
    );
    goog.dom.setTextContent(
        /** @type {Element} */ (this.outButton_.firstChild),
        ol.control.Zoom.RES.OUT_TEXT
    );
    goog.dom.append(container, this.inButton_, this.outButton_);

    var overlay = map.getStaticOverlay();
    if (goog.isDefAndNotNull(overlay)) {
        goog.dom.append(overlay, container);
    }
    goog.base(this, 'setMap', map);
};

/** @inheritDoc */
ol.control.Zoom.prototype.activate = function() {
    var active = goog.base(this, 'activate');
    if (active) {
        goog.events.listen(this.inButton_, 'click', this.handleIn, false, this);
        goog.events.listen(this.outButton_, 'click', this.handleOut, false, this);
    }
    return active;
};

/** @inheritDoc */
ol.control.Zoom.prototype.deactivate = function() {
    var inactive = goog.base(this, 'deactivate');
    if (inactive) {
        goog.events.unlisten(this.inButton_, 'click', this.handleIn, false, this);
        goog.events.unlisten(this.outButton_, 'click', this.handleOut, false, this);
    }
    return inactive;
};

/**
 * @param {Event} evt
 */
ol.control.Zoom.prototype.handleIn = function(evt) {
    this.map_.zoomIn();
    evt.preventDefault();
    evt.stopPropagation();
};

/**
 * @param {Event} evt
 */
ol.control.Zoom.prototype.handleOut = function(evt) {
    this.map_.zoomOut();
    evt.preventDefault();
    evt.stopPropagation();
};

ol.control.Zoom.prototype.destroy = function() {
    goog.dom.removeNode(goog.dom.getElementByClass(
        ol.control.Zoom.RES.CLS,
        /** @type {Element} */ (this.map_.getStaticOverlay())
    ));
    goog.base(this, 'destroy');
};

ol.control.addControl('zoom', ol.control.Zoom);

ol.control.Zoom.RES = {
    CLS: 'ol-control-zoom',
    IN_CLS: 'ol-control-zoom-in',
    OUT_CLS: 'ol-control-zoom-out',
    IN_TEXT: '+',
    OUT_TEXT: '\u2013'
};
<commit_msg>Using minus sign instead of ndash.<commit_after>goog.provide('ol.control.Zoom');

goog.require('ol.control.Control');

goog.require('goog.dom');

/**
 * @constructor
 * @extends {ol.control.Control}
 * @param {boolean|undefined} opt_autoActivate
 */
ol.control.Zoom = function(opt_autoActivate) {

    goog.base(this, opt_autoActivate);

    /**
     * @type {Node}
     */
    this.inButton_ = null;

    /**
     * @type {Node}
     */
    this.outButton_ = null;

    /**
     * Activate this control when it is added to a map.  Default is true.
     *
     * @type {boolean}
     */
    this.autoActivate_ =
        goog.isDef(opt_autoActivate) ? opt_autoActivate : true;

};
goog.inherits(ol.control.Zoom, ol.control.Control);

/**
 * @param {ol.Map} map
 */
ol.control.Zoom.prototype.setMap = function(map) {
    var container = goog.dom.createDom('div', ol.control.Zoom.RES.CLS);
    this.inButton_ = goog.dom.createDom(
        'div', ol.control.Zoom.RES.IN_CLS,
        goog.dom.createDom('a', {'href': '#zoomIn'})
    );
    goog.dom.setTextContent(
        /** @type {Element} */ (this.inButton_.firstChild),
        ol.control.Zoom.RES.IN_TEXT
    );
    this.outButton_ = goog.dom.createDom(
        'div', ol.control.Zoom.RES.OUT_CLS,
        goog.dom.createDom('a', {'href': '#zoomOut'})
    );
    goog.dom.setTextContent(
        /** @type {Element} */ (this.outButton_.firstChild),
        ol.control.Zoom.RES.OUT_TEXT
    );
    goog.dom.append(container, this.inButton_, this.outButton_);

    var overlay = map.getStaticOverlay();
    if (goog.isDefAndNotNull(overlay)) {
        goog.dom.append(overlay, container);
    }
    goog.base(this, 'setMap', map);
};

/** @inheritDoc */
ol.control.Zoom.prototype.activate = function() {
    var active = goog.base(this, 'activate');
    if (active) {
        goog.events.listen(this.inButton_, 'click', this.handleIn, false, this);
        goog.events.listen(this.outButton_, 'click', this.handleOut, false, this);
    }
    return active;
};

/** @inheritDoc */
ol.control.Zoom.prototype.deactivate = function() {
    var inactive = goog.base(this, 'deactivate');
    if (inactive) {
        goog.events.unlisten(this.inButton_, 'click', this.handleIn, false, this);
        goog.events.unlisten(this.outButton_, 'click', this.handleOut, false, this);
    }
    return inactive;
};

/**
 * @param {Event} evt
 */
ol.control.Zoom.prototype.handleIn = function(evt) {
    this.map_.zoomIn();
    evt.preventDefault();
    evt.stopPropagation();
};

/**
 * @param {Event} evt
 */
ol.control.Zoom.prototype.handleOut = function(evt) {
    this.map_.zoomOut();
    evt.preventDefault();
    evt.stopPropagation();
};

ol.control.Zoom.prototype.destroy = function() {
    goog.dom.removeNode(goog.dom.getElementByClass(
        ol.control.Zoom.RES.CLS,
        /** @type {Element} */ (this.map_.getStaticOverlay())
    ));
    goog.base(this, 'destroy');
};

ol.control.addControl('zoom', ol.control.Zoom);

ol.control.Zoom.RES = {
    CLS: 'ol-control-zoom',
    IN_CLS: 'ol-control-zoom-in',
    OUT_CLS: 'ol-control-zoom-out',
    IN_TEXT: '+',
    OUT_TEXT: '−'
};
<|endoftext|>