<commit_before>(function() {
// if google maps is not defined do not load the class
if(typeof(google) == "undefined" || typeof(google.maps) == "undefined") {
  return;
}

// helper to get pixel position from latlon
var Projector = function(map) { this.setMap(map); };
Projector.prototype = new google.maps.OverlayView();
Projector.prototype.draw = function() {};
Projector.prototype.latLngToPixel = function(point) {
  var p = this.getProjection();
  if(p) {
    return p.fromLatLngToContainerPixel(point);
  }
  return [0, 0];
};
Projector.prototype.pixelToLatLng = function(point) {
  var p = this.getProjection();
  if(p) {
    return p.fromContainerPixelToLatLng(point);
  }
  return [0, 0];
  //return this.map.getProjection().fromPointToLatLng(point);
};

var default_options = {
  opacity:        0.99,
  attribution:    "CartoDB",
  debug:          false,
  visible:        true,
  added:          false,
  tiler_domain:   "cartodb.com",
  tiler_port:     "80",
  tiler_protocol: "http",
  sql_api_domain:     "cartodb.com",
  sql_api_port:       "80",
  sql_api_protocol:   "http",
  extra_params:   {
  },
  cdn_url:        null,
  subdomains:     null
};

var OPACITY_FILTER = "progid:DXImageTransform.Microsoft.gradient(startColorstr=#00FFFFFF,endColorstr=#00FFFFFF)";

var CartoDBNamedMap = function(opts) {

  this.options = _.defaults(opts, default_options);
  this.tiles = 0;
  this.tilejson = null;
  this.interaction = [];

  if (!opts.named_map && !opts.sublayers) {
      throw new Error('cartodb-gmaps needs at least the named_map');
  }

  // Add CartoDB logo
  if (this.options.cartodb_logo != false)
    cdb.geo.common.CartoDBLogo.addWadus({ left: 74, bottom:8 }, 2000, this.options.map.getDiv());

  wax.g.connector.call(this, opts);

  // lovely wax connector overwrites options so set them again
  // TODO: remove wax.connector here
   _.extend(this.options, opts);
  this.projector = new Projector(opts.map);
  NamedMap.call(this, this.options.named_map, this.options);
  CartoDBLayerCommon.call(this);
  // precache
  this.update();
};

var CartoDBLayerGroup = function(opts) {

  this.options = _.defaults(opts, default_options);
  this.tiles = 0;
  this.tilejson = null;
  this.interaction = [];

  if (!opts.layer_definition && !opts.sublayers) {
      throw new Error('cartodb-leaflet needs at least the layer_definition or sublayer list');
  }

  // if only sublayers is available, generate layer_definition from it
  if(!opts.layer_definition) {
    opts.layer_definition = LayerDefinition.layerDefFromSubLayers(opts.sublayers);
  }

  // Add CartoDB logo
  if (this.options.cartodb_logo != false)
    cdb.geo.common.CartoDBLogo.addWadus({ left: 74, bottom:8 }, 2000, this.options.map.getDiv());

  wax.g.connector.call(this, opts);

  // lovely wax connector overwrites options so set them again
  // TODO: remove wax.connector here
   _.extend(this.options, opts);
  this.projector = new Projector(opts.map);
  LayerDefinition.call(this, opts.layer_definition, this.options);
  CartoDBLayerCommon.call(this);
  // precache
  this.update();
};

function setImageOpacityIE8(img, opacity) {
    var v = Math.round(opacity*100);
    if (v >= 99) {
      img.style.filter = OPACITY_FILTER;
    } else {
      img.style.filter = "alpha(opacity=" + (opacity) + ");";
    }
}

function CartoDBLayerGroupBase() {}

CartoDBLayerGroupBase.prototype.setOpacity = function(opacity) {
  if (isNaN(opacity) || opacity > 1 || opacity < 0) {
    throw new Error(opacity + ' is not a valid value, should be in [0, 1] range');
  }
  this.opacity = this.options.opacity = opacity;
  for(var key in this.cache) {
    var img = this.cache[key];
    img.style.opacity = opacity;
    setImageOpacityIE8(img, opacity);
  }

};

CartoDBLayerGroupBase.prototype.setAttribution = function() {};

CartoDBLayerGroupBase.prototype.getTile = function(coord, zoom, ownerDocument) {
  var EMPTY_GIF = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7";

  var self = this;
  var ie = 'ActiveXObject' in window,
      ielt9 = ie && !document.addEventListener;

  this.options.added = true;

  if(this.tilejson === null) {
    var key = zoom + '/' + coord.x + '/' + coord.y;
    var i = this.cache[key] = new Image(256, 256);
    i.src = EMPTY_GIF;
    i.setAttribute('gTileKey', key);
    i.style.opacity = this.options.opacity;
    return i;
  }

  var im = wax.g.connector.prototype.getTile.call(this, coord, zoom, ownerDocument);

  // in IE8 semi transparency does not work and needs filter
  if( ielt9 ) {
    setImageOpacityIE8(im, this.options.opacity);
  }
  im.style.opacity = this.options.opacity;
  if (this.tiles === 0) {
    this.loading && this.loading();
  }

  this.tiles++;

  var loadTime = cartodb.core.Profiler.metric('cartodb-js.tile.png.load.time').start();

  var finished = function() {
    loadTime.end();
    self.tiles--;
    if (self.tiles === 0) {
      self.finishLoading && self.finishLoading();
    }
  };
  im.onload = finished;
  im.onerror = function() {
    cartodb.core.Profiler.metric('cartodb-js.tile.png.error').inc();
    finished();
  }

  return im;
};

CartoDBLayerGroupBase.prototype.onAdd = function () {
  //this.update();
};

CartoDBLayerGroupBase.prototype.clear = function () {
  this._clearInteraction();
  self.finishLoading && self.finishLoading();
};

CartoDBLayerGroupBase.prototype.update = function (done) {
  var self = this;
  this.loading && this.loading();
  this.getTiles(function(urls, err) {
    if(urls) {
      self.tilejson = urls;
      self.options.tiles = urls.tiles;
      self.tiles = 0;
      self.cache = {};
      self._reloadInteraction();
      self.refreshView();
      self.ok && self.ok();
      done && done();
    } else {
      self.error && self.error(err)
    }
  });
};

CartoDBLayerGroupBase.prototype.refreshView = function() {
  var self = this;
  var map = this.options.map;
  map.overlayMapTypes.forEach(
    function(layer, i) {
      if (layer == self) {
        map.overlayMapTypes.setAt(i, self);
        return;
      }
    }
  );
}
CartoDBLayerGroupBase.prototype.onLayerDefinitionUpdated = function() {
    this.update();
}

CartoDBLayerGroupBase.prototype._checkLayer = function() {
  if (!this.options.added) {
    throw new Error('the layer is not still added to the map');
  }
}

CartoDBLayerGroupBase.prototype._findPos = function (map,o) {
  var curleft, cartop;
  curleft = curtop = 0;
  var obj = map.getDiv();

  var x, y;
  if (o.e.changedTouches && o.e.changedTouches.length > 0) {
    x = o.e.changedTouches[0].clientX + window.scrollX;
    y = o.e.changedTouches[0].clientY + window.scrollY;
  } else {
    x = o.e.clientX;
    y = o.e.clientY;
  }

  do {
    curleft += obj.offsetLeft;
    curtop += obj.offsetTop;
  } while (obj = obj.offsetParent);
  return new google.maps.Point(
      x - curleft,
      y - curtop
  );
};

CartoDBLayerGroupBase.prototype._manageOffEvents = function(map, o){
  if (this.options.featureOut) {
    return this.options.featureOut && this.options.featureOut(o.e, o.layer);
  }
};

CartoDBLayerGroupBase.prototype._manageOnEvents = function(map,o) {
  var point  = this._findPos(map, o);
  var latlng = this.projector.pixelToLatLng(point);
  var event_type = o.e.type.toLowerCase();

  switch (event_type) {
    case 'mousemove':
      if (this.options.featureOver) {
        return this.options.featureOver(o.e,latlng, point, o.data, o.layer);
      }
      break;

    case 'click':
    case 'touchend':
    case 'touchmove': // for some reason android browser does not send touchend
    case 'mspointerup':
      if (this.options.featureClick) {
        this.options.featureClick(o.e,latlng, point, o.data, o.layer);
      }
      break;
    default:
      break;
  }
}

// CartoDBLayerGroup type
CartoDBLayerGroup.Projector = Projector;
CartoDBLayerGroup.prototype = new wax.g.connector();
_.extend(CartoDBLayerGroup.prototype, LayerDefinition.prototype, CartoDBLayerGroupBase.prototype, CartoDBLayerCommon.prototype);
CartoDBLayerGroup.prototype.interactionClass = wax.g.interaction;

// CartoDBNamedMap
CartoDBNamedMap.prototype = new wax.g.connector();
_.extend(CartoDBNamedMap.prototype, NamedMap.prototype, CartoDBLayerGroupBase.prototype, CartoDBLayerCommon.prototype);
CartoDBNamedMap.prototype.interactionClass = wax.g.interaction;

// export
cdb.geo.CartoDBLayerGroupGMaps = CartoDBLayerGroup;
cdb.geo.CartoDBNamedMapGMaps = CartoDBNamedMap;

/*
 *
 *  cartodb layer group view
 *
 */

function LayerGroupView(base) {
  var GMapsCartoDBLayerGroupView = function(layerModel, gmapsMap) {
    var self = this;
    var hovers = [];

    _.bindAll(this, 'featureOut', 'featureOver', 'featureClick');

    // CartoDB new attribution,z
    // also we have the logo
    layerModel.attributes.attribution = cdb.config.get('cartodb_attributions');

    var opts = _.clone(layerModel.attributes);

    opts.map =  gmapsMap;

    var // preserve the user's callbacks
    _featureOver  = opts.featureOver,
    _featureOut   = opts.featureOut,
    _featureClick = opts.featureClick;

    var previousEvent;
    var eventTimeout = -1;

    opts.featureOver  = function(e, latlon, pxPos, data, layer) {
      if (!hovers[layer]) {
        self.trigger('layerenter', e, latlon, pxPos, data, layer);
      }
      hovers[layer] = 1;
      _featureOver  && _featureOver.apply(this, arguments);
      self.featureOver  && self.featureOver.apply(this, arguments);

      // if the event is the same than before just cancel the event
      // firing because there is a layer on top of it
      if (e.timeStamp === previousEvent) {
        clearTimeout(eventTimeout);
      }
      eventTimeout = setTimeout(function() {
        self.trigger('mouseover', e, latlon, pxPos, data, layer);
        self.trigger('layermouseover', e, latlon, pxPos, data, layer);
      }, 0);
      previousEvent = e.timeStamp;
    };

    opts.featureOut  = function(m, layer) {
      if (hovers[layer]) {
        self.trigger('layermouseout', layer);
      }
      hovers[layer] = 0;
      if(!_.any(hovers)) {
        self.trigger('mouseout');
      }
      _featureOut  && _featureOut.apply(this, arguments);
      self.featureOut  && self.featureOut.apply(this, arguments);
    };

    opts.featureClick  = _.debounce(function() {
      _featureClick  && _featureClick.apply(this, arguments);
      self.featureClick  && self.featureClick.apply(opts, arguments);
    }, 10);

    //CartoDBLayerGroup.call(this, opts);
    base.call(this, opts);
    cdb.geo.GMapsLayerView.call(this, layerModel, this, gmapsMap);
  };

  _.extend(
    GMapsCartoDBLayerGroupView.prototype,
    cdb.geo.GMapsLayerView.prototype,
    base.prototype,
    {

    _update: function() {
      this.setOptions(this.model.attributes);
    },

    reload: function() {
      this.model.invalidate();
    },

    remove: function() {
      cdb.geo.GMapsLayerView.prototype.remove.call(this);
      this.clear();
    },

    featureOver: function(e, latlon, pixelPos, data, layer) {
      // dont pass gmaps LatLng
      this.trigger('featureOver', e, [latlon.lat(), latlon.lng()], pixelPos, data, layer);
    },

    featureOut: function(e, layer) {
      this.trigger('featureOut', e, layer);
    },

    featureClick: function(e, latlon, pixelPos, data, layer) {
      // dont pass leaflet lat/lon
      this.trigger('featureClick', e, [latlon.lat(), latlon.lng()], pixelPos, data, layer);
    },

    error: function(e) {
      if(this.model) {
        //trigger the error form _checkTiles in the model
        this.model.trigger('error', e?e.errors:'unknown error');
        this.model.trigger('tileError', e?e.errors:'unknown error');
      }
    },

    ok: function(e) {
      this.model.trigger('tileOk');
    },

    tilesOk: function(e) {
      this.model.trigger('tileOk');
    },

    loading: function() {
      this.trigger("loading");
    },

    finishLoading: function() {
      this.trigger("load");
    }

  });
  return GMapsCartoDBLayerGroupView;
}

cdb.geo.GMapsCartoDBLayerGroupView = LayerGroupView(CartoDBLayerGroup);
cdb.geo.GMapsCartoDBNamedMapView = LayerGroupView(CartoDBNamedMap);

cdb.geo.CartoDBNamedMapGMaps = CartoDBNamedMap;
/**
* gmaps cartodb layer
*/

})();
<commit_msg>Fix GMaps and IEMobile click event:<commit_after>(function() {
// if google maps is not defined do not load the class
if(typeof(google) == "undefined" || typeof(google.maps) == "undefined") {
  return;
}

// helper to get pixel position from latlon
var Projector = function(map) { this.setMap(map); };
Projector.prototype = new google.maps.OverlayView();
Projector.prototype.draw = function() {};
Projector.prototype.latLngToPixel = function(point) {
  var p = this.getProjection();
  if(p) {
    return p.fromLatLngToContainerPixel(point);
  }
  return [0, 0];
};
Projector.prototype.pixelToLatLng = function(point) {
  var p = this.getProjection();
  if(p) {
    return p.fromContainerPixelToLatLng(point);
  }
  return [0, 0];
  //return this.map.getProjection().fromPointToLatLng(point);
};

var default_options = {
  opacity:        0.99,
  attribution:    "CartoDB",
  debug:          false,
  visible:        true,
  added:          false,
  tiler_domain:   "cartodb.com",
  tiler_port:     "80",
  tiler_protocol: "http",
  sql_api_domain:     "cartodb.com",
  sql_api_port:       "80",
  sql_api_protocol:   "http",
  extra_params:   {
  },
  cdn_url:        null,
  subdomains:     null
};

var OPACITY_FILTER = "progid:DXImageTransform.Microsoft.gradient(startColorstr=#00FFFFFF,endColorstr=#00FFFFFF)";

var CartoDBNamedMap = function(opts) {

  this.options = _.defaults(opts, default_options);
  this.tiles = 0;
  this.tilejson = null;
  this.interaction = [];

  if (!opts.named_map && !opts.sublayers) {
      throw new Error('cartodb-gmaps needs at least the named_map');
  }

  // Add CartoDB logo
  if (this.options.cartodb_logo != false)
    cdb.geo.common.CartoDBLogo.addWadus({ left: 74, bottom:8 }, 2000, this.options.map.getDiv());

  wax.g.connector.call(this, opts);

  // lovely wax connector overwrites options so set them again
  // TODO: remove wax.connector here
   _.extend(this.options, opts);
  this.projector = new Projector(opts.map);
  NamedMap.call(this, this.options.named_map, this.options);
  CartoDBLayerCommon.call(this);
  // precache
  this.update();
};

var CartoDBLayerGroup = function(opts) {

  this.options = _.defaults(opts, default_options);
  this.tiles = 0;
  this.tilejson = null;
  this.interaction = [];

  if (!opts.layer_definition && !opts.sublayers) {
      throw new Error('cartodb-leaflet needs at least the layer_definition or sublayer list');
  }

  // if only sublayers is available, generate layer_definition from it
  if(!opts.layer_definition) {
    opts.layer_definition = LayerDefinition.layerDefFromSubLayers(opts.sublayers);
  }

  // Add CartoDB logo
  if (this.options.cartodb_logo != false)
    cdb.geo.common.CartoDBLogo.addWadus({ left: 74, bottom:8 }, 2000, this.options.map.getDiv());

  wax.g.connector.call(this, opts);

  // lovely wax connector overwrites options so set them again
  // TODO: remove wax.connector here
   _.extend(this.options, opts);
  this.projector = new Projector(opts.map);
  LayerDefinition.call(this, opts.layer_definition, this.options);
  CartoDBLayerCommon.call(this);
  // precache
  this.update();
};

function setImageOpacityIE8(img, opacity) {
    var v = Math.round(opacity*100);
    if (v >= 99) {
      img.style.filter = OPACITY_FILTER;
    } else {
      img.style.filter = "alpha(opacity=" + (opacity) + ");";
    }
}

function CartoDBLayerGroupBase() {}

CartoDBLayerGroupBase.prototype.setOpacity = function(opacity) {
  if (isNaN(opacity) || opacity > 1 || opacity < 0) {
    throw new Error(opacity + ' is not a valid value, should be in [0, 1] range');
  }
  this.opacity = this.options.opacity = opacity;
  for(var key in this.cache) {
    var img = this.cache[key];
    img.style.opacity = opacity;
    setImageOpacityIE8(img, opacity);
  }

};

CartoDBLayerGroupBase.prototype.setAttribution = function() {};

CartoDBLayerGroupBase.prototype.getTile = function(coord, zoom, ownerDocument) {
  var EMPTY_GIF = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7";

  var self = this;
  var ie = 'ActiveXObject' in window,
      ielt9 = ie && !document.addEventListener;

  this.options.added = true;

  if(this.tilejson === null) {
    var key = zoom + '/' + coord.x + '/' + coord.y;
    var i = this.cache[key] = new Image(256, 256);
    i.src = EMPTY_GIF;
    i.setAttribute('gTileKey', key);
    i.style.opacity = this.options.opacity;
    return i;
  }

  var im = wax.g.connector.prototype.getTile.call(this, coord, zoom, ownerDocument);

  // in IE8 semi transparency does not work and needs filter
  if( ielt9 ) {
    setImageOpacityIE8(im, this.options.opacity);
  }
  im.style.opacity = this.options.opacity;
  if (this.tiles === 0) {
    this.loading && this.loading();
  }

  this.tiles++;

  var loadTime = cartodb.core.Profiler.metric('cartodb-js.tile.png.load.time').start();

  var finished = function() {
    loadTime.end();
    self.tiles--;
    if (self.tiles === 0) {
      self.finishLoading && self.finishLoading();
    }
  };
  im.onload = finished;
  im.onerror = function() {
    cartodb.core.Profiler.metric('cartodb-js.tile.png.error').inc();
    finished();
  }

  return im;
};

CartoDBLayerGroupBase.prototype.onAdd = function () {
  //this.update();
};

CartoDBLayerGroupBase.prototype.clear = function () {
  this._clearInteraction();
  self.finishLoading && self.finishLoading();
};

CartoDBLayerGroupBase.prototype.update = function (done) {
  var self = this;
  this.loading && this.loading();
  this.getTiles(function(urls, err) {
    if(urls) {
      self.tilejson = urls;
      self.options.tiles = urls.tiles;
      self.tiles = 0;
      self.cache = {};
      self._reloadInteraction();
      self.refreshView();
      self.ok && self.ok();
      done && done();
    } else {
      self.error && self.error(err)
    }
  });
};

CartoDBLayerGroupBase.prototype.refreshView = function() {
  var self = this;
  var map = this.options.map;
  map.overlayMapTypes.forEach(
    function(layer, i) {
      if (layer == self) {
        map.overlayMapTypes.setAt(i, self);
        return;
      }
    }
  );
}
CartoDBLayerGroupBase.prototype.onLayerDefinitionUpdated = function() {
    this.update();
}

CartoDBLayerGroupBase.prototype._checkLayer = function() {
  if (!this.options.added) {
    throw new Error('the layer is not still added to the map');
  }
}

CartoDBLayerGroupBase.prototype._findPos = function (map,o) {
  var curleft, cartop;
  curleft = curtop = 0;
  var obj = map.getDiv();

  var x, y;
  if (o.e.changedTouches && o.e.changedTouches.length > 0 && (o.e.changedTouches[0] !== undefined) ) {
    x = o.e.changedTouches[0].clientX + window.scrollX;
    y = o.e.changedTouches[0].clientY + window.scrollY;
  } else {
    x = o.e.clientX;
    y = o.e.clientY;
  }

  do {
    curleft += obj.offsetLeft;
    curtop += obj.offsetTop;
  } while (obj = obj.offsetParent);
  return new google.maps.Point(
      x - curleft,
      y - curtop
  );
};

CartoDBLayerGroupBase.prototype._manageOffEvents = function(map, o){
  if (this.options.featureOut) {
    return this.options.featureOut && this.options.featureOut(o.e, o.layer);
  }
};

CartoDBLayerGroupBase.prototype._manageOnEvents = function(map,o) {
  var point  = this._findPos(map, o);
  var latlng = this.projector.pixelToLatLng(point);
  var event_type = o.e.type.toLowerCase();

  switch (event_type) {
    case 'mousemove':
      if (this.options.featureOver) {
        return this.options.featureOver(o.e,latlng, point, o.data, o.layer);
      }
      break;

    case 'click':
    case 'touchend':
    case 'touchmove': // for some reason android browser does not send touchend
    case 'mspointerup':
    case 'pointerup':
    case 'pointermove':
      if (this.options.featureClick) {
        this.options.featureClick(o.e,latlng, point, o.data, o.layer);
      }
      break;
    default:
      break;
  }
}

// CartoDBLayerGroup type
CartoDBLayerGroup.Projector = Projector;
CartoDBLayerGroup.prototype = new wax.g.connector();
_.extend(CartoDBLayerGroup.prototype, LayerDefinition.prototype, CartoDBLayerGroupBase.prototype, CartoDBLayerCommon.prototype);
CartoDBLayerGroup.prototype.interactionClass = wax.g.interaction;

// CartoDBNamedMap
CartoDBNamedMap.prototype = new wax.g.connector();
_.extend(CartoDBNamedMap.prototype, NamedMap.prototype, CartoDBLayerGroupBase.prototype, CartoDBLayerCommon.prototype);
CartoDBNamedMap.prototype.interactionClass = wax.g.interaction;

// export
cdb.geo.CartoDBLayerGroupGMaps = CartoDBLayerGroup;
cdb.geo.CartoDBNamedMapGMaps = CartoDBNamedMap;

/*
 *
 *  cartodb layer group view
 *
 */

function LayerGroupView(base) {
  var GMapsCartoDBLayerGroupView = function(layerModel, gmapsMap) {
    var self = this;
    var hovers = [];

    _.bindAll(this, 'featureOut', 'featureOver', 'featureClick');

    // CartoDB new attribution,z
    // also we have the logo
    layerModel.attributes.attribution = cdb.config.get('cartodb_attributions');

    var opts = _.clone(layerModel.attributes);

    opts.map =  gmapsMap;

    var // preserve the user's callbacks
    _featureOver  = opts.featureOver,
    _featureOut   = opts.featureOut,
    _featureClick = opts.featureClick;

    var previousEvent;
    var eventTimeout = -1;

    opts.featureOver  = function(e, latlon, pxPos, data, layer) {
      if (!hovers[layer]) {
        self.trigger('layerenter', e, latlon, pxPos, data, layer);
      }
      hovers[layer] = 1;
      _featureOver  && _featureOver.apply(this, arguments);
      self.featureOver  && self.featureOver.apply(this, arguments);

      // if the event is the same than before just cancel the event
      // firing because there is a layer on top of it
      if (e.timeStamp === previousEvent) {
        clearTimeout(eventTimeout);
      }
      eventTimeout = setTimeout(function() {
        self.trigger('mouseover', e, latlon, pxPos, data, layer);
        self.trigger('layermouseover', e, latlon, pxPos, data, layer);
      }, 0);
      previousEvent = e.timeStamp;
    };

    opts.featureOut  = function(m, layer) {
      if (hovers[layer]) {
        self.trigger('layermouseout', layer);
      }
      hovers[layer] = 0;
      if(!_.any(hovers)) {
        self.trigger('mouseout');
      }
      _featureOut  && _featureOut.apply(this, arguments);
      self.featureOut  && self.featureOut.apply(this, arguments);
    };

    opts.featureClick  = _.debounce(function() {
      _featureClick  && _featureClick.apply(this, arguments);
      self.featureClick  && self.featureClick.apply(opts, arguments);
    }, 10);

    //CartoDBLayerGroup.call(this, opts);
    base.call(this, opts);
    cdb.geo.GMapsLayerView.call(this, layerModel, this, gmapsMap);
  };

  _.extend(
    GMapsCartoDBLayerGroupView.prototype,
    cdb.geo.GMapsLayerView.prototype,
    base.prototype,
    {

    _update: function() {
      this.setOptions(this.model.attributes);
    },

    reload: function() {
      this.model.invalidate();
    },

    remove: function() {
      cdb.geo.GMapsLayerView.prototype.remove.call(this);
      this.clear();
    },

    featureOver: function(e, latlon, pixelPos, data, layer) {
      // dont pass gmaps LatLng
      this.trigger('featureOver', e, [latlon.lat(), latlon.lng()], pixelPos, data, layer);
    },

    featureOut: function(e, layer) {
      this.trigger('featureOut', e, layer);
    },

    featureClick: function(e, latlon, pixelPos, data, layer) {
      // dont pass leaflet lat/lon
      this.trigger('featureClick', e, [latlon.lat(), latlon.lng()], pixelPos, data, layer);
    },

    error: function(e) {
      if(this.model) {
        //trigger the error form _checkTiles in the model
        this.model.trigger('error', e?e.errors:'unknown error');
        this.model.trigger('tileError', e?e.errors:'unknown error');
      }
    },

    ok: function(e) {
      this.model.trigger('tileOk');
    },

    tilesOk: function(e) {
      this.model.trigger('tileOk');
    },

    loading: function() {
      this.trigger("loading");
    },

    finishLoading: function() {
      this.trigger("load");
    }

  });
  return GMapsCartoDBLayerGroupView;
}

cdb.geo.GMapsCartoDBLayerGroupView = LayerGroupView(CartoDBLayerGroup);
cdb.geo.GMapsCartoDBNamedMapView = LayerGroupView(CartoDBNamedMap);

cdb.geo.CartoDBNamedMapGMaps = CartoDBNamedMap;
/**
* gmaps cartodb layer
*/

})();
<|endoftext|>


<commit_before>/**
 * @fileoverview Type annotations for the React library.
 *
 * Will be automatically included as a source (not externs) file by
 * ReactCompilerPass. The contents of this file should be inert (i.e. interfaces
 * and typedefs only) such that it compiles down to nothing.
 *
 * Based on https://github.com/facebook/flow/blob/master/lib/react.js
 */

/**
 * @typedef {!Function}
 * @template T
 */
var ReactClass;

/**
 * @interface
 * @template T
 */
function ReactElement() {}

/**
 * @interface
 */
function ReactComponent() {}

/**
 * @return {Object}
 */
ReactComponent.prototype.getInitialState = function() {};

/**
 * @param {Object} props
 * @param {function(): void=} callback
 * @return {void}
 */
ReactComponent.prototype.setProps = function(props, callback) {};

/**
 * @param {Object} props
 * @param {function(): void=} callback
 * @return {void}
 */
ReactComponent.prototype.replaceProps = function(props, callback) {};

/**
 * @param {Object} state
 * @param {function(): void=} callback
 * @return {void}
 */
ReactComponent.prototype.setState = function(state, callback) {};

/**
 * @param {Object} state
 * @param {function(): void=} callback
 * @return {void}
 */
ReactComponent.prototype.replaceState = function(state, callback) {};

/**
 * @return {ReactElement}
 */
ReactComponent.prototype.render = function(state, callback) {};

/**
 * @param {function(): void=} callback
 * @return {void}
 */
ReactComponent.prototype.forceUpdate = function(callback) {};

/**
 * @return {Element}
 */
ReactComponent.prototype.getDOMNode = function() {};

/**
 * @return {boolean}
 */
ReactComponent.prototype.isMounted = function() {};

// Component lifecycle/delegate methods that may be implemented. Intentionally
// does not include the context parameter that is passed to some methods, since
// it's undocumented. Implementations can still add it (and it will not be
// flagged as an error).

/**
 * @return {void}
 */
ReactComponent.prototype.componentWillMount = function() {};

/**
 * @return {void}
 */
ReactComponent.prototype.componentDidMount = function() {};

/**
 * @param {Object} nextProps
 * @return {void}
 */
ReactComponent.prototype.componentWillReceiveProps = function(nextProps) {};

/**
 * @param {Object} nextProps
 * @param {Object} nextState
 * @return {boolean}
 */
ReactComponent.prototype.shouldComponentUpdate = function(nextProps, nextState) {};

/**
 * @param {Object} nextProps
 * @param {Object} nextState
 * @return {void}
 */
ReactComponent.prototype.componentWillUpdate = function(nextProps, nextState) {};

/**
 * @param {Object} prevProps
 * @param {Object} prevState
 * @return {void}
 */
ReactComponent.prototype.componentDidUpdate = function(prevProps, prevState) {};

/**
 * @return {void}
 */
ReactComponent.prototype.componentWillUnmount = function() {};

/**
 * @typedef {
 *   boolean|number|string|ReactElement|
 *   Array.<boolean>|Array.<number>|Array.<string>|Array.<ReactElement>
 * }
 */
var ReactChild;

/**
 * @interface
 */
function ReactStaticFunctions() {}

/**
 * @param {{render: function(): ReactElement}} specification
 * @return {ReactClass}
 */
ReactStaticFunctions.prototype.createClass = function(specification) {};

/**
 * @param {T} mixin
 * @return {T}
 * @template T
 */
ReactStaticFunctions.prototype.createMixin = function(mixin) {};

/**
 * @param {(ReactClass.<T>|string|number)} type
 * @param {Object=} props
 * @param {...ReactChild} children
 * @return {ReactElement.<T>}
 * @template T
 */
ReactStaticFunctions.prototype.createElement = function(type, props, children) {};

/**
 * @param {ReactElement.<T>} nextElement
 * @param {Element} container
 * @param {function()=} callback
 * @return {T}
 * @template T
 */
ReactStaticFunctions.prototype.render = function(nextElement, container, callback) {};
<commit_msg>Add rest of React static functions.<commit_after>/**
 * @fileoverview Type annotations for the React library.
 *
 * Will be automatically included as a source (not externs) file by
 * ReactCompilerPass. The contents of this file should be inert (i.e. interfaces
 * and typedefs only) such that it compiles down to nothing.
 *
 * Based on https://github.com/facebook/flow/blob/master/lib/react.js
 */

/**
 * @typedef {!Function}
 * @template T
 */
var ReactClass;

/**
 * @interface
 * @template T
 */
function ReactElement() {}

/**
 * @interface
 */
function ReactComponent() {}

/**
 * @return {Object}
 */
ReactComponent.prototype.getInitialState = function() {};

/**
 * @param {Object} props
 * @param {function(): void=} callback
 * @return {void}
 */
ReactComponent.prototype.setProps = function(props, callback) {};

/**
 * @param {Object} props
 * @param {function(): void=} callback
 * @return {void}
 */
ReactComponent.prototype.replaceProps = function(props, callback) {};

/**
 * @param {Object} state
 * @param {function(): void=} callback
 * @return {void}
 */
ReactComponent.prototype.setState = function(state, callback) {};

/**
 * @param {Object} state
 * @param {function(): void=} callback
 * @return {void}
 */
ReactComponent.prototype.replaceState = function(state, callback) {};

/**
 * @return {ReactElement}
 */
ReactComponent.prototype.render = function(state, callback) {};

/**
 * @param {function(): void=} callback
 * @return {void}
 */
ReactComponent.prototype.forceUpdate = function(callback) {};

/**
 * @return {Element}
 */
ReactComponent.prototype.getDOMNode = function() {};

/**
 * @return {boolean}
 */
ReactComponent.prototype.isMounted = function() {};

// Component lifecycle/delegate methods that may be implemented. Intentionally
// does not include the context parameter that is passed to some methods, since
// it's undocumented. Implementations can still add it (and it will not be
// flagged as an error).

/**
 * @return {void}
 */
ReactComponent.prototype.componentWillMount = function() {};

/**
 * @return {void}
 */
ReactComponent.prototype.componentDidMount = function() {};

/**
 * @param {Object} nextProps
 * @return {void}
 */
ReactComponent.prototype.componentWillReceiveProps = function(nextProps) {};

/**
 * @param {Object} nextProps
 * @param {Object} nextState
 * @return {boolean}
 */
ReactComponent.prototype.shouldComponentUpdate = function(nextProps, nextState) {};

/**
 * @param {Object} nextProps
 * @param {Object} nextState
 * @return {void}
 */
ReactComponent.prototype.componentWillUpdate = function(nextProps, nextState) {};

/**
 * @param {Object} prevProps
 * @param {Object} prevState
 * @return {void}
 */
ReactComponent.prototype.componentDidUpdate = function(prevProps, prevState) {};

/**
 * @return {void}
 */
ReactComponent.prototype.componentWillUnmount = function() {};

/**
 * @typedef {
 *   boolean|number|string|ReactElement|
 *   Array.<boolean>|Array.<number>|Array.<string>|Array.<ReactElement>
 * }
 */
var ReactChild;

/**
 * @interface
 */
function ReactStaticFunctions() {}

/**
 * @param {boolean} shouldUseTouch
 * @return {void}
 */
ReactStaticFunctions.prototype.initializeTouchEvents = function(shouldUseTouch) {};

/**
 * @param {{render: function(): ReactElement}} specification
 * @return {ReactClass}
 */
ReactStaticFunctions.prototype.createClass = function(specification) {};

/**
 * @param {T} mixin
 * @return {T}
 * @template T
 */
ReactStaticFunctions.prototype.createMixin = function(mixin) {};

/**
 * @param {(ReactClass.<T>|string|number)} type
 * @param {Object=} props
 * @param {...ReactChild} children
 * @return {ReactElement.<T>}
 * @template T
 */
ReactStaticFunctions.prototype.createElement = function(type, props, children) {};

/**
 * @param {(ReactClass.<T>|string|number)} type
 * @return {function(Object=, ...ReactChild): ReactElement.<T>}
 * @template T
 */
ReactStaticFunctions.prototype.createFactory = function(type) {};

/**
 * @param {(ReactElement|Element)} componentOrElement
 * @return {Element}
 */
ReactStaticFunctions.prototype.findDOMNode = function(componentOrElement) {};

/**
 * @param {ReactElement.<T>} element
 * @param {Element} container
 * @param {function()=} callback
 * @return {T}
 * @template T
 */
ReactStaticFunctions.prototype.render = function(element, container, callback) {};

/**
 * @param {ReactElement} element
 * @return {string}
 */
ReactStaticFunctions.prototype.renderToString = function(element) {};

/**
 * @param {ReactElement} element
 * @return {string}
 */
ReactStaticFunctions.prototype.renderToStaticMarkup = function(element) {};

/**
 * @param {Element} container
 * @return {boolean}
 */
ReactStaticFunctions.prototype.unmountComponentAtNode = function(container) {};

/**
 * @param {Object} element
 * @return {boolean}
 */
ReactStaticFunctions.prototype.isValidElement = function(element) {};
<|endoftext|>


<commit_before>/*
 * Wrapping differnt memcached clients
 * */

var mc = require('mc');

module.exports = function Memcached() {
    this.client = new mc.Client("localhost", mc.Adapter.raw);
    this.connect = function() {
        this.client.connect(function() {
              console.log("Connected to the localhost memcache on port 11211!");
        });
    }

    this.store = function(key, data, callback) {
        callback = callback || function(error, result) {
            if (error) {
                console.error(error);
            } else {
                console.log("" + result.length + " bytes are memcached");
            }
        };
        console.log("memcaching data");
        this.client.set(key, data, { flags: 0, exptime: 60*60*3}, callback);
    }

    this.get = function(key, callback) {
        this.client.get(key, function(err, response) {
            if (err) callback(err, null); else {
                callback(null, response[key].buffer);
            }
        });
    }
}
<commit_msg>fixed output for memcached wrapper SET method<commit_after>/*
 * Wrapping differnt memcached clients
 * */

var mc = require('mc');

module.exports = function Memcached() {
    this.client = new mc.Client("localhost", mc.Adapter.raw);
    this.connect = function() {
        this.client.connect(function() {
              console.log("Connected to the localhost memcache on port 11211!");
        });
    }

    this.store = function(key, data, callback) {
        callback = callback || function(error, result) {
            if (error) {
                console.error(error);
            } else {
                console.log("Memcached response: " + result);
            }
        };
        console.log("memcaching data");
        this.client.set(key, data, { flags: 0, exptime: 60*60*3}, callback);
    }

    this.get = function(key, callback) {
        this.client.get(key, function(err, response) {
            if (err) callback(err, null); else {
                callback(null, response[key].buffer);
            }
        });
    }
}
<|endoftext|>


<commit_before>// jshint node: true
'use strict';

var fs = require('fs'),
    sysPath = require('path'),
    os = require('os'),
    chalk = require('chalk'),
    which = require('which'),
    anyspawn = require('anyspawn'),
    new_branch = '__umd_features__',
    push = Array.prototype.push,
    slice = Array.prototype.slice;

require('fs').readdir('../lib', function(err) {
    if (err) {
        anyspawn.spawn('npm run prepublish', {stdio: 'inherit'}, function(err) {
            if (err) throw err;
            setup(sysPath.join(__dirname, '..'));
        });
    }
});

function setup(projectRoot, done) {
    // https://ariejan.net/2009/10/26/how-to-create-and-apply-a-patch-with-git/
    var config = {
            patches: {},
            project: {
                root: projectRoot
            }
        },
        projectModules = config.project.modules = sysPath.join(projectRoot, 'node_modules'),
        projectBrunch = config.project.brunch = sysPath.join(projectModules, 'brunch'),
        projectLodash = config.project.lodash = sysPath.join(projectModules, 'lodash'),
        patchesFolder = config.patches.folder = sysPath.join(projectRoot, 'patches'),
        username = require('username').sync(),
        is_new_branch = new RegExp('\\*\\s+' + new_branch + '(?:\\n|$)'),
        has_new_branch = new RegExp('(?:^|\n)' + new_branch + '(?:\\n|$)');

    // make such patch executable exists
    which.sync('patch');

    var tasks = [],
        options = {
            stdio: 'inherit',
            cwd: projectBrunch
        };
    if (fs.existsSync(projectBrunch)) {
        anyspawn.spawn('git rev-parse', options, function(code) {
            if (code) {
                throw new Error('"' + projectBrunch + '" exists and is not a git repository');
            }

            anyspawn.exec('git branch -l', options, function(err, data) {
                if (err) {
                    throw new Error('"' + projectBrunch + '": cannot list branches');
                }
                var commands;
                if (is_new_branch.test(data)) {
                    commands = [
                        'git reset --hard HEAD~2',
                        'git checkout master',
                        'git branch -D "' + new_branch + '"'
                    ];
                } else if (has_new_branch.test(data)) {
                    commands = [
                        'git reset --hard HEAD',
                        'git checkout master',
                        'git branch -D "' + new_branch + '"'
                    ];
                } else {
                    commands = [
                        'git reset --hard HEAD',
                        'git checkout master'
                    ];
                }

                commands = commands.map(function(element) {
                    return [element, {
                        cwd: projectBrunch
                    }];
                });

                anyspawn.spawnSeries(commands, function(err) {
                    if (err) {
                        done(err);
                        return;
                    }
                    install(tasks, config, done);
                });
            });
        });
    } else {
        tasks.push(['git clone https://github.com/brunch/brunch.git', {
            cwd: sysPath.dirname(projectBrunch)
        }]);
        install(tasks, config, done);
    }
}

function install(tasks, config, done) {
    if ('function' !== typeof done) {
        done = emptyFn;
    }

    var brunchPatches = [
            'brunch-1.8.x-anymatch_feature',
            'brunch-1.8.x-completer_feature',
            'brunch-1.8.x-config_compiler_feature',
            'brunch-1.8.x-module_not_found_inaccuracy_fix'
        ],
        filePatches = [
            ['node_modules/log4js/lib/log4js.js', 'log4js-v0.6.x-shutdown_fix.patch'],
            ['node_modules/highlight.js/lib/languages/handlebars.js', 'hljs_hbs-8.7.0_fix.patch']
        ],
        projectBrunch = config.project.brunch,
        projectLodash = config.project.lodash,
        projectRoot = config.project.root,
        patchesFolder = config.patches.folder,
        patchFile;

    push.apply(tasks, [
        ['git checkout tags/1.8.5', {
            cwd: projectBrunch
        }],
        ['git checkout -b "' + new_branch + '"', {
            cwd: projectBrunch
        }]
    ]);

    for (var i = 0, _len = brunchPatches.length; i < _len; i++) {
        patchFile = sysPath.relative(projectBrunch, sysPath.join(patchesFolder, brunchPatches[i] + '.patch'));
        tasks.push(['git apply -v --check ' + anyspawn.quoteArg(patchFile), {
            cwd: projectBrunch
        }], ['git apply ' + anyspawn.quoteArg(patchFile), {
            cwd: projectBrunch
        }]);
    }

    push.apply(tasks, [
        ['npm install --production', {
            cwd: projectLodash
        }],
        ['npm install --production', {
            cwd: projectBrunch
        }],
        ['rm -rf .git', {
            cwd: projectBrunch
        }],
        ['npm install --production --ignore-scripts', {
            cwd: projectRoot
        }]
    ]);

    anyspawn.spawnSeries(tasks, {
        stdio: 'inherit'
    }, function(err) {
        if (err) {
            done(err);
            return;
        }

        patchSeries(filePatches, config, done);
    });
}

function patchSeries(patches, config, done) {
    var i = -1,
        _len = patches.length,
        projectRoot = config.project.root,
        patchesFolder = config.patches.folder;

    iterate(0);

    function iterate(err) {
        var file, patch;
        if (err === 0 && ++i < _len) {
            file = sysPath.relative(projectRoot, sysPath.join(projectRoot, patches[i][0]));
            patch = sysPath.relative(projectRoot, sysPath.join(patchesFolder, patches[i][1]));
            anyspawn.spawn('patch ' + anyspawn.quoteArg(file) + ' < ' + anyspawn.quoteArg(patch), {
                cwd: projectRoot,
                stdio: 'inherit'
            }, iterate);
        } else {
            done(err);
        }
    }
}

function emptyFn() {}<commit_msg>try fix node v4 npm 3.4.x nested install<commit_after>// jshint node: true
'use strict';

var fs = require('fs'),
    sysPath = require('path'),
    os = require('os'),
    chalk = require('chalk'),
    which = require('which'),
    anyspawn = require('anyspawn'),
    new_branch = '__umd_features__',
    push = Array.prototype.push,
    slice = Array.prototype.slice;

require('fs').readdir('../lib', function(err) {
    if (err) {
        anyspawn.spawn('npm run prepublish', {
            stdio: 'inherit'
        }, function(err) {
            if (err) throw err;
            setup(sysPath.join(__dirname, '..'));
        });
    }
});

function setup(projectRoot, done) {
    // https://ariejan.net/2009/10/26/how-to-create-and-apply-a-patch-with-git/
    var config = {
            patches: {},
            project: {
                root: projectRoot
            }
        },
        projectModules = config.project.modules = sysPath.join(projectRoot, 'node_modules'),
        projectBrunch = config.project.brunch = sysPath.join(projectModules, 'brunch'),
        projectLodash = config.project.lodash = sysPath.join(projectModules, 'lodash'),
        patchesFolder = config.patches.folder = sysPath.join(projectRoot, 'patches'),
        username = require('username').sync(),
        is_new_branch = new RegExp('\\*\\s+' + new_branch + '(?:\\n|$)'),
        has_new_branch = new RegExp('(?:^|\n)' + new_branch + '(?:\\n|$)');

    // make such patch executable exists
    which.sync('patch');

    var tasks = [
            // with node v4 and npm 3.4.0 and npm 3.4.1, nested postinstall script is launched before end of all packages installation
            ['npm install --production --ignore-scripts', {
                cwd: projectRoot
            }]
        ],
        options = {
            stdio: 'inherit',
            cwd: projectBrunch
        };
    if (fs.existsSync(projectBrunch)) {
        anyspawn.spawn('git rev-parse', options, function(code) {
            if (code) {
                throw new Error('"' + projectBrunch + '" exists and is not a git repository');
            }

            anyspawn.exec('git branch -l', options, function(err, data) {
                if (err) {
                    throw new Error('"' + projectBrunch + '": cannot list branches');
                }
                var commands;
                if (is_new_branch.test(data)) {
                    commands = [
                        'git reset --hard HEAD~2',
                        'git checkout master',
                        'git branch -D "' + new_branch + '"'
                    ];
                } else if (has_new_branch.test(data)) {
                    commands = [
                        'git reset --hard HEAD',
                        'git checkout master',
                        'git branch -D "' + new_branch + '"'
                    ];
                } else {
                    commands = [
                        'git reset --hard HEAD',
                        'git checkout master'
                    ];
                }

                commands = commands.map(function(element) {
                    return [element, {
                        cwd: projectBrunch
                    }];
                });

                anyspawn.spawnSeries(commands, function(err) {
                    if (err) {
                        done(err);
                        return;
                    }
                    install(tasks, config, done);
                });
            });
        });
    } else {
        tasks.push(['git clone https://github.com/brunch/brunch.git', {
            cwd: sysPath.dirname(projectBrunch)
        }]);
        install(tasks, config, done);
    }
}

function install(tasks, config, done) {
    if ('function' !== typeof done) {
        done = emptyFn;
    }

    var brunchPatches = [
            'brunch-1.8.x-anymatch_feature',
            'brunch-1.8.x-completer_feature',
            'brunch-1.8.x-config_compiler_feature',
            'brunch-1.8.x-module_not_found_inaccuracy_fix'
        ],
        filePatches = [
            ['node_modules/log4js/lib/log4js.js', 'log4js-v0.6.x-shutdown_fix.patch'],
            ['node_modules/highlight.js/lib/languages/handlebars.js', 'hljs_hbs-8.7.0_fix.patch']
        ],
        projectBrunch = config.project.brunch,
        projectLodash = config.project.lodash,
        projectRoot = config.project.root,
        patchesFolder = config.patches.folder,
        patchFile;

    push.apply(tasks, [
        ['git checkout tags/1.8.5', {
            cwd: projectBrunch
        }],
        ['git checkout -b "' + new_branch + '"', {
            cwd: projectBrunch
        }]
    ]);

    for (var i = 0, _len = brunchPatches.length; i < _len; i++) {
        patchFile = sysPath.relative(projectBrunch, sysPath.join(patchesFolder, brunchPatches[i] + '.patch'));
        tasks.push(['git apply -v --check ' + anyspawn.quoteArg(patchFile), {
            cwd: projectBrunch
        }], ['git apply ' + anyspawn.quoteArg(patchFile), {
            cwd: projectBrunch
        }]);
    }

    push.apply(tasks, [
        ['npm install --production', {
            cwd: projectLodash
        }],
        ['npm install --production', {
            cwd: projectBrunch
        }]
    ]);

    anyspawn.spawnSeries(tasks, {
        stdio: 'inherit'
    }, function(err) {
        if (err) {
            done(err);
            return;
        }

        patchSeries(filePatches, config, done);
    });
}

function patchSeries(patches, config, done) {
    var i = -1,
        _len = patches.length,
        projectRoot = config.project.root,
        patchesFolder = config.patches.folder;

    iterate(0);

    function iterate(err) {
        var file, patch;
        if (err === 0 && ++i < _len) {
            file = sysPath.relative(projectRoot, sysPath.join(projectRoot, patches[i][0]));
            patch = sysPath.relative(projectRoot, sysPath.join(patchesFolder, patches[i][1]));
            anyspawn.spawn('patch ' + anyspawn.quoteArg(file) + ' < ' + anyspawn.quoteArg(patch), {
                cwd: projectRoot,
                stdio: 'inherit'
            }, iterate);
        } else {
            done(err);
        }
    }
}

function emptyFn() {}<|endoftext|>


<commit_before>#!/usr/bin/env node

var fs = require('fs');
var path = require('path');
var execSync = require('child_process').execSync;

var $ = require('cheerio');
var fromEntries = require('object.fromentries');

if (process.argv.length !== 3) {
	throw new RangeError('please provide a year');
}
var year = parseInt(process.argv[2]);
if (year < 2016) {
	throw new RangeError('ES2016+ only');
}
var edition = year - 2009;

var specHTMLurl = new URL('https://raw.githubusercontent.com/tc39/ecma262/es' + year + '/spec.html');

var specHTML = String(execSync('curl --silent ' + specHTMLurl, { stdio: 'inherit' }));

var root = $(specHTML);

var aOps = root.filter('[aoid]').add(root.find('[aoid]'));

var missings = [];

var entries = aOps.toArray().map(function (x) {
  var op = $(x);
  var aoid = op.attr('aoid');
  var id = op.attr('id');

  if (!id) {
    id = op.closest('[id]').attr('id');
  }

  if (!id) {
    missings.push(aoid);
  }

  return [
    aoid,
    'https://ecma-international.org/ecma-262/' + edition + '.0/#' + id
  ];
});

if (missings.length > 0) {
  console.error('Missing URLs:', missings);
  process.exit(1);
}

entries.sort(function (a, b) { return a[0].localeCompare(b[0]); });

var obj = fromEntries(entries);

var outputPath = path.join('operations', year + '.js');
fs.writeFileSync(outputPath, '\'use strict\';\n\nmodule.exports = ' + JSON.stringify(obj, null, '\t')+ ';\n');

console.log('npx eslint --quiet --fix ' + outputPath);
execSync('npx eslint --quiet --fix ' + outputPath);
<commit_msg>[meta] fix getOps script<commit_after>#!/usr/bin/env node

var fs = require('fs');
var path = require('path');
var execSync = require('child_process').execSync;

var $ = require('cheerio');
var fromEntries = require('object.fromentries');

if (process.argv.length !== 3) {
	throw new RangeError('please provide a year');
}
var year = parseInt(process.argv[2]);
if (year < 2016) {
	throw new RangeError('ES2016+ only');
}
var edition = year - 2009;

var specHTMLurl = new URL('https://raw.githubusercontent.com/tc39/ecma262/es' + year + '/spec.html');

var specHTML = String(execSync('curl -q --silent ' + specHTMLurl, { maxBuffer: Infinity }));

var root = $(specHTML);

var aOps = root.filter('[aoid]').add(root.find('[aoid]'));

var missings = [];

var entries = aOps.toArray().map(function (x) {
  var op = $(x);
  var aoid = op.attr('aoid');
  var id = op.attr('id');

  if (!id) {
    id = op.closest('[id]').attr('id');
  }

  if (!id) {
    missings.push(aoid);
  }

  return [
    aoid,
    'https://ecma-international.org/ecma-262/' + edition + '.0/#' + id
  ];
});

if (missings.length > 0) {
  console.error('Missing URLs:', missings);
  process.exit(1);
}

entries.sort(function (a, b) { return a[0].localeCompare(b[0]); });

var obj = fromEntries(entries);

var outputPath = path.join('operations', year + '.js');
fs.writeFileSync(outputPath, '\'use strict\';\n\nmodule.exports = ' + JSON.stringify(obj, null, '\t')+ ';\n');

console.log('npx eslint --quiet --fix ' + outputPath);
execSync('npx eslint --quiet --fix ' + outputPath);
<|endoftext|>


<commit_before>/*
 * Tick object handles all the process/display related to tick streaming
 *
 * We request tick stream for particular underlying to update current spot
 *
 *
 * Usage:
 * use `Tick.detail` to populate this object
 *
 * then use
 *
 * `Tick.quote()` to get current spot quote
 * `Tick.id()` to get the unique for current stream
 * `Tick.epoch()` to get the tick epoch time
 * 'Tick.display()` to display current spot
 */
var Tick = (function () {
    'use strict';

    var quote = '',
        id = '',
        epoch = '',
        errorMessage = '',
        bufferedIds = {};

    var details = function (data) {
        errorMessage = '';

        if (data) {
            var tick = data['tick'];
            if (tick['error']) {
                errorMessage = tick['error']['message'];
            } else {
                quote = tick['quote'];
                id = tick['id'];
                epoch = tick['epoch'];

                if (!bufferedIds.hasOwnProperty(id)) {
                    bufferedIds[id] = moment().utc().unix();
                }
            }
        }
    };

    var display = function () {
        var spotElement = document.getElementById('spot');
        var message = '';
        if (errorMessage) {
            message = errorMessage;
        } else {
            message = quote;
        }
        displayPriceMovement(spotElement, spotElement.textContent, message);
        spotElement.textContent = message;
    };

    return {
        details: details,
        display: display,
        quote: function () { return quote; },
        id: function () { return id; },
        epoch: function () { return epoch; },
        errorMessage: function () { return errorMessage; },
        bufferedIds: function () { return bufferedIds; }
    };
})();
<commit_msg>handle error for tick response<commit_after>/*
 * Tick object handles all the process/display related to tick streaming
 *
 * We request tick stream for particular underlying to update current spot
 *
 *
 * Usage:
 * use `Tick.detail` to populate this object
 *
 * then use
 *
 * `Tick.quote()` to get current spot quote
 * `Tick.id()` to get the unique for current stream
 * `Tick.epoch()` to get the tick epoch time
 * 'Tick.display()` to display current spot
 */
var Tick = (function () {
    'use strict';

    var quote = '',
        id = '',
        epoch = '',
        errorMessage = '',
        bufferedIds = {};

    var details = function (data) {
        errorMessage = '';

        if (data) {
            if (data['error']) {
                errorMessage = data['error']['message'];
            } else {
                var tick = data['tick'];
                quote = tick['quote'];
                id = tick['id'];
                epoch = tick['epoch'];

                if (!bufferedIds.hasOwnProperty(id)) {
                    bufferedIds[id] = moment().utc().unix();
                }
            }
        }
    };

    var display = function () {
        var spotElement = document.getElementById('spot');
        var message = '';
        if (errorMessage) {
            message = errorMessage;
        } else {
            message = quote;
        }
        displayPriceMovement(spotElement, spotElement.textContent, message);
        spotElement.textContent = message;
    };

    return {
        details: details,
        display: display,
        quote: function () { return quote; },
        id: function () { return id; },
        epoch: function () { return epoch; },
        errorMessage: function () { return errorMessage; },
        bufferedIds: function () { return bufferedIds; }
    };
})();
<|endoftext|>


<commit_before>import classNames from 'classnames/dedupe';
import React from 'react';

class PageHeaderActions extends React.Component {
  render() {
    let {props: {actions}} = this;

    let actionElements = actions.map(function (action, index) {
      if (action.node) {
        return action.node;
      }

      let classes = classNames('button button-rounded', action.className);

      return (
        <button className={classes} key={index} onClick={action.clickHandler}>
          {action.label}
        </button>
      );
    });

    return (

        {actionElements}

    );
  }
}

PageHeaderActions.defaultProps = {
  actions: []
};

const classProps = React.PropTypes.oneOfType([
  React.PropTypes.array,
  React.PropTypes.object,
  React.PropTypes.string
]);

PageHeaderActions.propTypes = {
  actions: React.PropTypes.arrayOf(
    React.PropTypes.shape({
      className: classProps,
      clickHandler: React.PropTypes.func,
      label: React.PropTypes.node
    })
  )
};

module.exports = PageHeaderActions;
<commit_msg>Update page header actions component to use new action buttons<commit_after>import classNames from 'classnames/dedupe';
import React from 'react';
import {Tooltip} from 'reactjs-components';

import Icon from './Icon';
import PageHeaderActionsMenu from './PageHeaderActionsMenu';

class PageHeaderActions extends React.Component {

  renderActionsMenu() {
    const {actions} = this.props;

    if (actions.length > 0) {
      const dropdownElements = actions.map(function (action, index) {
        if (React.isValidElement(action)) {
          return action;
        }

        return (

            {action.label}

        );
      });

      return (
        <PageHeaderActionsMenu>
          {dropdownElements}
        </PageHeaderActionsMenu>
      );
    }
  }

  renderAddButton() {
    const {addButton} = this.props;
    if (addButton != null) {
      const {label, onItemSelect, className} = addButton;
      const buttonClasses = classNames(
          'button button-link flush-left flush-right',
          className
      );

      const button = (
        <button className={buttonClasses} onClick={onItemSelect}>
          <Icon id="plus" size="mini" />
        </button>
      );

      if (label != null) {
        return (
          <Tooltip content={label}>{button}</Tooltip>
        );
      }

      return button;
    }
  }

  render() {
    return (

          {this.renderAddButton()}
          {this.renderActionsMenu()}

    );
  }
}

PageHeaderActions.defaultProps = {
  actions: []
};

const classProps = React.PropTypes.oneOfType([
  React.PropTypes.array,
  React.PropTypes.object,
  React.PropTypes.string
]);

PageHeaderActions.propTypes = {
  addButton: React.PropTypes.shape({
    className: classProps,
    clickHandler: React.PropTypes.func,
    label: React.PropTypes.node
  }),
  actions: React.PropTypes.arrayOf(
    React.PropTypes.oneOf(
      React.PropTypes.node,
      React.PropTypes.shape({
        className: classProps,
        clickHandler: React.PropTypes.func.isRequired,
        label: React.PropTypes.node.isRequired
      })
    )
  )
};

module.exports = PageHeaderActions;
<|endoftext|>


<commit_before>import React, { Component } from 'react';
//React.PropTypes is deprecated as of React v15.5. Please use the prop-types library instead.
//source: https://facebook.github.io/react/docs/typechecking-with-proptypes.html
import PropTypes from 'prop-types';
import { View } from 'react-native';
import Svg,{
    Circle,
    G,
    Line,
    Text
} from 'react-native-svg';
import _ from 'lodash';

class NetworkGraph extends Component
{
  findCircleCenterCoords(index) {
    //for a given index of a circle, where is its center.
    const {circleTitles, containerHeight, containerWidth, distanceFromCenter, selectedCircleIndex} = this.props;
    const degreeDifference = Number(360/(circleTitles.length-1));
    if(index>=selectedCircleIndex)
    index = index-1
    let xCordinate = containerWidth/2 + Math.cos((index*degreeDifference - 90)* Math.PI / 180.0)*distanceFromCenter
    let yCordinate = containerHeight/2 + Math.sin((index*degreeDifference - 90)* Math.PI / 180.0)*distanceFromCenter
    return {
      xCordinate:xCordinate,
      yCordinate:yCordinate
    }
  }

  circleClicked(index) {
    const {onCircleClick} = this.props;
    return function() {
      onCircleClick(index);
    }
  }

  addBackgroundLines(connectionType) {
    const { containerHeight, containerWidth, circleTitles, connections, otherCircleLinesColor, selectedCircleIndex } = this.props;
    let allCircleLines = Object.keys(connections).map( (fromCircleIndex)=> {
      if(fromCircleIndex==selectedCircleIndex)
      return null;
      let connectionsForCircle = connections[fromCircleIndex];

      let currentCircleCoordinates = this.findCircleCenterCoords(fromCircleIndex);
      let linesForCircle = connectionsForCircle.map((toCircleIndex)=>{
        let targetCircleCoordinates = this.findCircleCenterCoords(toCircleIndex);
        if(toCircleIndex===selectedCircleIndex)  //if its connected to the circle currently selected targetCircleCoordinates will be the center of the drawable board.
        targetCircleCoordinates = {
          xCordinate:containerWidth/2,
          yCordinate:containerHeight/2
        }

        return <Line
          x1={currentCircleCoordinates.xCordinate}
          y1={currentCircleCoordinates.yCordinate}
          x2={targetCircleCoordinates.xCordinate}
          y2={targetCircleCoordinates.yCordinate}
          stroke={otherCircleLinesColor}
          strokeWidth="1"/>
      });

      return linesForCircle;
    });
    return allCircleLines;
  }

  addSelectedCircleLines() {
    const { circleTitles, connections, containerHeight, containerWidth, selectedCircleIndex, selectedCircleLinesColor} = this.props;
    let selectCircleAttachees = connections[selectedCircleIndex] || [];
    let allLinesForCurrentCircle = selectCircleAttachees.map( (toCircleIndex, index)=> {
      let targetCircleCoordinates = this.findCircleCenterCoords(toCircleIndex);
      return <Line
          x1={containerWidth/2}
          y1={containerHeight/2}
          x2={targetCircleCoordinates.xCordinate}
          y2={targetCircleCoordinates.yCordinate}
          stroke={selectedCircleLinesColor}
          strokeWidth="3"
          key={'selected_circle_line'+index}/>
    });
    return allLinesForCurrentCircle;
  }

  addCircles() {
    const {circleTitles, connections, centralCircleFillColor, otherCirclesRadius, otherCircleTextColor, otherCircleFillColor, selectedCircleIndex} = this.props;
    let circleElements = circleTitles.map( (title, index)=> {
        if(index===selectedCircleIndex)
        return null;

        let circleCoOrds = this.findCircleCenterCoords(index);
        let selectCircleAttachees = connections[selectedCircleIndex] || [];
        let circleStrokeColor = otherCircleFillColor;
        if(_.includes(selectCircleAttachees, index))
        circleStrokeColor = centralCircleFillColor
        return (
          <G key={"circle"+index} onPress={this.circleClicked(index)}>
            <Circle cx={circleCoOrds.xCordinate} cy={circleCoOrds.yCordinate} r={otherCirclesRadius} stroke={circleStrokeColor} strokeWidth="2" fill={otherCircleFillColor}/>
            <Text x={circleCoOrds.xCordinate-10} y={circleCoOrds.yCordinate-10} fill={otherCircleTextColor} stroke={otherCircleTextColor}>{title}</Text>
          </G>
        )
    });
    return circleElements;
  }

  render() {
    const { centralCircleRadius, centralCircleStrokeColor, centralCircleFillColor, centralCircleTextColor, containerHeight, containerWidth, circleTitles, selectedCircleIndex} = this.props
    const centralCircleText = circleTitles[selectedCircleIndex];
    return (
      <View style={{height:containerHeight, width:containerWidth}}>
        <Svg
          height={containerHeight}
          width={containerWidth}>
            {this.addBackgroundLines()}
            {this.addSelectedCircleLines()}
            <G>
              <Circle cx={containerWidth/2} cy={containerHeight/2} r={centralCircleRadius} stroke={centralCircleStrokeColor} strokeWidth="4" fill={centralCircleFillColor} style={{borderWidth:5}} textAnchor="middle"/>
              <Text x={containerWidth/2 - 10} y={containerHeight/2 - 10} fill={centralCircleTextColor} stroke={centralCircleTextColor}>{centralCircleText}</Text>
            </G>
            {this.addCircles()}
        </Svg>
      </View>
    )
  }
}

NetworkGraph.propTypes = {
  circleTitles:PropTypes.array.isRequired,
  selectedCircleIndex:PropTypes.number.isRequired,
  connections:PropTypes.object.isRequired,
  onCircleClick:PropTypes.func.isRequired,
  containerHeight:PropTypes.number,
  containerWidth:PropTypes.number,
  centralCircleRadius:PropTypes.number,
  otherCirclesRadius:PropTypes.number,
  distanceFromCenter:PropTypes.number,
  selectedCircleLinesColor:PropTypes.string,
  otherCircleLinesColor:PropTypes.string,
  centralCircleStrokeColor:PropTypes.string,
  centralCircleFillColor:PropTypes.string,
  centralCircleTextColor:PropTypes.string,
  otherCircleTextColor:PropTypes.string,
  otherCircleFillColor:PropTypes.string
}

NetworkGraph.defaultProps = {
  containerHeight:500,
  containerWidth:500,
  centralCircleRadius:60,
  otherCirclesRadius:35,
  distanceFromCenter:200,
  selectedCircleLinesColor:'#f59f02',
  otherCircleLinesColor:'white',
  centralCircleStrokeColor:'#24a195',
  centralCircleFillColor:'#18B0A2',
  centralCircleTextColor:'white',
  otherCircleTextColor:'white',
  otherCircleFillColor:'black'
}

export default NetworkGraph;
<commit_msg>changed default property<commit_after>import React, { Component } from 'react';
//React.PropTypes is deprecated as of React v15.5. Please use the prop-types library instead.
//source: https://facebook.github.io/react/docs/typechecking-with-proptypes.html
import PropTypes from 'prop-types';
import { View } from 'react-native';
import Svg,{
    Circle,
    G,
    Line,
    Text
} from 'react-native-svg';
import _ from 'lodash';

class NetworkGraph extends Component
{
  findCircleCenterCoords(index) {
    //for a given index of a circle, where is its center.
    const {circleTitles, containerHeight, containerWidth, distanceFromCenter, selectedCircleIndex} = this.props;
    const degreeDifference = Number(360/(circleTitles.length-1));
    if(index>=selectedCircleIndex)
    index = index-1
    let xCordinate = containerWidth/2 + Math.cos((index*degreeDifference - 90)* Math.PI / 180.0)*distanceFromCenter
    let yCordinate = containerHeight/2 + Math.sin((index*degreeDifference - 90)* Math.PI / 180.0)*distanceFromCenter
    return {
      xCordinate:xCordinate,
      yCordinate:yCordinate
    }
  }

  circleClicked(index) {
    const {onCircleClick} = this.props;
    return function() {
      onCircleClick(index);
    }
  }

  addBackgroundLines(connectionType) {
    const { containerHeight, containerWidth, circleTitles, connections, otherCircleLinesColor, selectedCircleIndex } = this.props;
    let allCircleLines = Object.keys(connections).map( (fromCircleIndex)=> {
      if(fromCircleIndex==selectedCircleIndex)
      return null;
      let connectionsForCircle = connections[fromCircleIndex];

      let currentCircleCoordinates = this.findCircleCenterCoords(fromCircleIndex);
      let linesForCircle = connectionsForCircle.map((toCircleIndex)=>{
        let targetCircleCoordinates = this.findCircleCenterCoords(toCircleIndex);
        if(toCircleIndex===selectedCircleIndex)  //if its connected to the circle currently selected targetCircleCoordinates will be the center of the drawable board.
        targetCircleCoordinates = {
          xCordinate:containerWidth/2,
          yCordinate:containerHeight/2
        }

        return <Line
          x1={currentCircleCoordinates.xCordinate}
          y1={currentCircleCoordinates.yCordinate}
          x2={targetCircleCoordinates.xCordinate}
          y2={targetCircleCoordinates.yCordinate}
          stroke={otherCircleLinesColor}
          strokeWidth="1"/>
      });

      return linesForCircle;
    });
    return allCircleLines;
  }

  addSelectedCircleLines() {
    const { circleTitles, connections, containerHeight, containerWidth, selectedCircleIndex, selectedCircleLinesColor} = this.props;
    let selectCircleAttachees = connections[selectedCircleIndex] || [];
    let allLinesForCurrentCircle = selectCircleAttachees.map( (toCircleIndex, index)=> {
      let targetCircleCoordinates = this.findCircleCenterCoords(toCircleIndex);
      return <Line
          x1={containerWidth/2}
          y1={containerHeight/2}
          x2={targetCircleCoordinates.xCordinate}
          y2={targetCircleCoordinates.yCordinate}
          stroke={selectedCircleLinesColor}
          strokeWidth="3"
          key={'selected_circle_line'+index}/>
    });
    return allLinesForCurrentCircle;
  }

  addCircles() {
    const {circleTitles, connections, centralCircleFillColor, otherCirclesRadius, otherCircleTextColor, otherCircleFillColor, selectedCircleIndex} = this.props;
    let circleElements = circleTitles.map( (title, index)=> {
        if(index===selectedCircleIndex)
        return null;

        let circleCoOrds = this.findCircleCenterCoords(index);
        let selectCircleAttachees = connections[selectedCircleIndex] || [];
        let circleStrokeColor = otherCircleFillColor;
        if(_.includes(selectCircleAttachees, index))
        circleStrokeColor = centralCircleFillColor
        return (
          <G key={"circle"+index} onPress={this.circleClicked(index)}>
            <Circle cx={circleCoOrds.xCordinate} cy={circleCoOrds.yCordinate} r={otherCirclesRadius} stroke={circleStrokeColor} strokeWidth="2" fill={otherCircleFillColor}/>
            <Text x={circleCoOrds.xCordinate-10} y={circleCoOrds.yCordinate-10} fill={otherCircleTextColor} stroke={otherCircleTextColor}>{title}</Text>
          </G>
        )
    });
    return circleElements;
  }

  render() {
    const { centralCircleRadius, centralCircleStrokeColor, centralCircleFillColor, centralCircleTextColor, containerHeight, containerWidth, circleTitles, selectedCircleIndex} = this.props
    const centralCircleText = circleTitles[selectedCircleIndex];
    return (
      <View style={{height:containerHeight, width:containerWidth}}>
        <Svg
          height={containerHeight}
          width={containerWidth}>
            {this.addBackgroundLines()}
            {this.addSelectedCircleLines()}
            <G>
              <Circle cx={containerWidth/2} cy={containerHeight/2} r={centralCircleRadius} stroke={centralCircleStrokeColor} strokeWidth="4" fill={centralCircleFillColor} style={{borderWidth:5}} textAnchor="middle"/>
              <Text x={containerWidth/2 - 10} y={containerHeight/2 - 10} fill={centralCircleTextColor} stroke={centralCircleTextColor}>{centralCircleText}</Text>
            </G>
            {this.addCircles()}
        </Svg>
      </View>
    )
  }
}

NetworkGraph.propTypes = {
  circleTitles:PropTypes.array.isRequired,
  selectedCircleIndex:PropTypes.number.isRequired,
  connections:PropTypes.object.isRequired,
  onCircleClick:PropTypes.func.isRequired,
  containerHeight:PropTypes.number,
  containerWidth:PropTypes.number,
  centralCircleRadius:PropTypes.number,
  otherCirclesRadius:PropTypes.number,
  distanceFromCenter:PropTypes.number,
  selectedCircleLinesColor:PropTypes.string,
  otherCircleLinesColor:PropTypes.string,
  centralCircleStrokeColor:PropTypes.string,
  centralCircleFillColor:PropTypes.string,
  centralCircleTextColor:PropTypes.string,
  otherCircleTextColor:PropTypes.string,
  otherCircleFillColor:PropTypes.string
}

NetworkGraph.defaultProps = {
  containerHeight:500,
  containerWidth:500,
  centralCircleRadius:60,
  otherCirclesRadius:35,
  distanceFromCenter:200,
  selectedCircleLinesColor:'#f59f02',
  otherCircleLinesColor:'black',
  centralCircleStrokeColor:'#24a195',
  centralCircleFillColor:'#18B0A2',
  centralCircleTextColor:'white',
  otherCircleTextColor:'white',
  otherCircleFillColor:'black'
}

export default NetworkGraph;
<|endoftext|>


<commit_before>/* global google */

const gMaps = require('../../location/googleMaps')

let popup = null

const MapBuilder = function () {
  const self = this

  self.updateMarkers = (items) => {
    items
      .forEach((p, i) => {
        const infoWindow = gMaps.buildInfoWindow(self.buildInfoWindowMarkup(p))

        self.infoWindows.push(infoWindow)

        const marker = gMaps.buildMarker(self.getLocation(p), self.map)

        marker.customFields = {
          mapIndex: i
        }

        marker.addListener('click', function () {
          document.querySelectorAll('.card__gmaps-container')
            .forEach((p) => p.parentNode.removeChild(p))

          const location = self.getLocation(p)

          const position = new google.maps.LatLng(location.latitude, location.longitude)

          popup = new gMaps.Popup(
            location.latitude,
            location.longitude,
            self.buildInfoWindowMarkup(p))

          popup.setMap(self.map)
          self.map.setCenter(position)
          if (self.container) {
            self.container.markerClicked(this.customFields.mapIndex)
          }
        })

        self.markers.push(marker)
      })
  }

  self.infoWindows = []
  self.markers = []

  self.itemSelected = function (item) {
    const itemIndex = item.mapIndex()
    self.infoWindows[itemIndex].open(self.map, self.markers[itemIndex])
    self.infoWindows
      .filter((iw, i) => i !== itemIndex)
      .forEach((iw, i) => {
        iw.close()
      })
  }

  self.update = function (items) {
    self.infoWindows = []

    self.markers
      .forEach((m) => {
        m.setVisible(false)
        m.setMap(null)
      })

    self.markers = []

    self.updateMarkers(items)
  }

  self.init = function (items, userLocation, container, buildInfoWindowMarkup, getLocation = (p) => {
    return { latitude: p.latitude(), longitude: p.longitude() }
  }, customOptions = {}) {

    self.map = gMaps.buildMap(userLocation, customOptions)

    self.container = container
    self.buildInfoWindowMarkup = buildInfoWindowMarkup
    self.getLocation = getLocation

    self.markers
      .forEach((m) => m.setMap(null))

    self.infoWindows = []
    self.markers = []

    self.updateMarkers(items)
  }
}

module.exports = MapBuilder
<commit_msg>fix accom google maps issue<commit_after>/* global google */

const gMaps = require('../../location/googleMaps')

let popup = null

const MapBuilder = function () {
  const self = this

  self.updateMarkers = (items) => {
    items
      .forEach((p, i) => {
        const infoWindow = gMaps.buildInfoWindow(self.buildInfoWindowMarkup(p))

        self.infoWindows.push(infoWindow)

        const marker = gMaps.buildMarker(self.getLocation(p), self.map)

        marker.customFields = {
          mapIndex: i
        }

        marker.addListener('click', function () {
          document.querySelectorAll('.card__gmaps-container')
            .forEach((p) => p.parentNode.removeChild(p))

          const location = self.getLocation(p)

          const position = new google.maps.LatLng(location.latitude, location.longitude)

          popup = new gMaps.Popup(
            location.latitude,
            location.longitude,
            self.buildInfoWindowMarkup(p))

          popup.setMap(self.map)
          self.map.setCenter(position)
          if (self.container) {
            self.container.markerClicked(this.customFields.mapIndex)
          }
        })

        self.markers.push(marker)
      })
  }

  self.infoWindows = []
  self.markers = []

  self.itemSelected = function (item) {
    const itemIndex = item.mapIndex()
    self.infoWindows[itemIndex].open(self.map, self.markers[itemIndex])
    self.infoWindows
      .filter((iw, i) => i !== itemIndex)
      .forEach((iw, i) => {
        iw.close()
      })
  }

  self.update = function (items) {
    self.infoWindows = []

    self.markers
      .forEach((m) => {
        m.setVisible(false)
        m.setMap(null)
      })

    self.markers = []

    self.updateMarkers(items)
  }

  self.init = function (items, userLocation, container, buildInfoWindowMarkup, getLocation = (p) => {
    return { latitude: p.latitude(), longitude: p.longitude() }
  }, customOptions = {}) {
    self.map = gMaps.buildMap(userLocation, customOptions)

    self.container = container
    self.buildInfoWindowMarkup = buildInfoWindowMarkup
    self.getLocation = getLocation

    self.markers
      .forEach((m) => m.setMap(null))

    self.infoWindows = []
    self.markers = []

    self.updateMarkers(items)
  }
}

module.exports = MapBuilder
<|endoftext|>


<commit_before>'use strict';

var Leverage = require('leverage')
  , https = require('https')
  , fuse = require('fusing')
  , ip = require('ip');

/**
 * Add defaults to the supplied options. The following options are available:
 *
 * - redis: The Redis instance we should use to store data
 * - namespace: The namespace prefix to prevent collision's.
 * - interval: Expire interval to keep the server alive in Redis
 * - timeout: Timeout for sparks who are alive.
 * - latency: Time it takes for our Redis commands to execute.
 *
 * @param {Primus} primus The Primus instance that received the plugin.
 * @param {Object} options Configuration.
 * @returns {Object} Options.
 * @api public
 */
function Metroplex(primus, options) {
  if (!(this instanceof Metroplex)) return new Metroplex(primus, options);

  options = options || {};
  primus = primus || {};

  var parsed = this.parse(primus.server);

  this.fuse();

  this.redis = options.redis || require('redis').createClient();
  this.namespace = (options.namespace || 'metroplex') +':';
  this.interval = options.interval || 5 * 60 * 1000;
  this.timeout = options.timeout || 30 * 60;
  this.latency = options.latency || 2000;
  this.leverage = new Leverage(this.redis, {
    namespace: this.namespace
  });

  if (parsed || options.address) {
    this.register(options.address || parsed);
  }
}

fuse(Metroplex, require('eventemitter3'));

/**
 * Parse our the connection URL from a given HTTP server instance or string.
 *
 * @param {Server} server HTTP or HTTPS server instance we should read address from
 * @returns {String} The address
 * @api public
 */
Metroplex.readable('parse', function parse(server) {
  if ('string' === typeof server || !server) return server || '';

  var secure = server instanceof https.Server || 'function' === typeof server.addContext
    , address = server.address ? server.address() : undefined;

  //
  // If the HTTP server isn't listening yet to a port number the result of
  // .address will be undefined. We can only get the location
  //
  if (!address) return '';

  //
  // Seriously, 0.0.0.0 is basically localhost. Get the correct address for it.
  //
  if (address.address === '0.0.0.0') {
    address.address = ip.address();
  }

  return 'http'+ (secure ? 's' : '') +'://'+ address.address +':'+ address.port;
});

/**
 * Register a new server/address in the Metroplex registry.
 *
 * @param {String|Server} address The server to add.
 * @param {Function} fn Optional callback;
 * @returns {Metroplex}
 * @api public
 */
Metroplex.readable('register', function register(address, fn) {
  var metroplex = this;

  metroplex.address = this.parse(address || metroplex.address);
  if (!metroplex.address) {
    if (fn) fn();
    return this;
  }

  metroplex.leverage.annihilate(metroplex.address, function annihilate(err) {
    if (err) {
      if (fn) return fn(err);
      return metroplex.emit('error', err);
    }

    metroplex.redis.multi()
      .setex(metroplex.namespace + metroplex.address, metroplex.interval, Date.now())
      .sadd(metroplex.namespace +'servers', metroplex.address)
    .exec(function register(err) {
      if (err) {
        if (fn) return fn(err);
        return metroplex.emit('error', err);
      }

      metroplex.emit('register', metroplex.address);
      metroplex.setInterval();

      if (fn) fn(err, metroplex.address);
    });
  });
});

/**
 * Remove a server/address from the Metroplex registry.
 *
 * @param {String|Server} address The server to remove.
 * @param {Function} fn Optional callback.
 * @returns {Metroplex}
 * @api public
 */
Metroplex.readable('unregister', function unregister(address, fn) {
  var metroplex = this;

  address = this.parse(address || metroplex.address);
  if (!metroplex.address) {
    if (fn) fn();
    return this;
  }

  metroplex.leverage.annihilate(address, function annihilate(err) {
    if (err) {
      if (fn) return fn(err);
      return metroplex.emit('error', err);
    }

    metroplex.emit('unregister', address);

    if (metroplex.timer) clearInterval(metroplex.timer);
    if (fn) fn(err, address);
  });

  return this;
});

/**
 * Add a new connection for our registered address.
 *
 * @param {Spark} spark The connection/spark from Primus.
 * @returns {Metroplex}
 * @api public
 */
Metroplex.readable('connect', function connect(spark) {
  this.redis.multi()
    .hset(this.namespace +'sparks', spark.id, this.address)
    .sadd(this.namespace + this.address +':sparks', spark.id)
  .exec();

  return this;
});

/**
 * Remove a connection for our registered address.
 *
 * @param {Spark} spark The connection/spark from Primus.
 * @returns {Metroplex}
 * @api public
 */
Metroplex.readable('disconnect', function disconnect(spark) {
  this.redis.multi()
    .hdel(this.namespace +'sparks', spark.id)
    .srem(this.namespace + this.address +':sparks', spark.id)
  .exec();

  return this;
});

/**
 * Get all current registered servers except our selfs.
 *
 * @param {Function} fn Callback
 * @returns {Metroplex}
 * @api public
 */
Metroplex.readable('servers', function servers(self, fn) {
  var metroplex = this;

  if ('boolean' !== typeof self) {
    fn = self;
    self = 0;
  }

  this.redis.smembers(this.namespace +'servers', function smembers(err, members) {
    if (self) return fn(err, members);

    fn(err, (members || []).filter(function filter(address) {
      return address !== metroplex.address;
    }));
  });

  return this;
});

/**
 * Get the server address for a given spark id.
 *
 * @param {String} id The spark id who's server address we want to retrieve.
 * @param {Function} fn Callback
 * @returns {Metroplex}
 * @api public
 */
Metroplex.readable('spark', function spark(id, fn) {
  this.redis.hget(this.namespace +'sparks', id, fn);
  return this;
});

/**
 * Get all server addresses for the given spark ids.
 *
 * @param {Array} args The spark id's we need to look up
 * @param {Function} fn Callback.
 * @returns {Metroplex}
 * @api public
 */
Metroplex.readable('sparks', function sparks(args, fn) {
  args.push(fn);
  args.shift(this.namespace +'sparks');
  this.redis.hmget.apply(this.redis, args);

  return this;
});

/**
 * We need to make sure that this server is alive, the most easy and dirty way
 * of doing this is setting an interval which bumps the expire of our
 * dedicated server key. If we go off line, the key will expire and we will be
 * K.O. The value indicates the last "ping" that we got from the node server
 * so you can see when the last update was.
 *
 * @api private
 */
Metroplex.readable('setInterval', function setIntervals() {
  if (this.timer) clearInterval(this.timer);

  var alive = this.namespace + this.address +':alive'
    , redis = this.redis
    , metroplex = this;

  this.timer = setInterval(function interval() {
    //
    // Redis expects the expire value in seconds instead of milliseconds so we
    // need to correct our interval.
    //
    redis.setex(alive, metroplex.interval / 1000, Date.now());

    metroplex.servers(function servers(err, list) {
      if (err) return metroplex.emit('error', err);

      list.forEach(function expired(address) {
        redis.get(metroplex.namespace + address, function get(err, stamp) {
          if (err || Date.now() - +stamp < metroplex.interval) return;

          metroplex.leverage.annihilate(address, function murdered(err) {
            if (err) return metroplex.emit('error', err);
          });
        });
      });
    });
  }, this.interval - this.latency);
});

//
// Expose the Metroplex library/registry/api
//
module.exports = Metroplex;
<commit_msg>[fix] Ensure that our directory for lua scripts has been set<commit_after>'use strict';

var Leverage = require('leverage')
  , https = require('https')
  , fuse = require('fusing')
  , ip = require('ip');

//
// Ensure that the directory for our custom lua scripts is set correctly.
//
Leverage.scripts = Leverage.scripts.concat(
  Leverage.introduce(require('path').join(__dirname, 'lua'), Leverage.prototype)
);

/**
 * Add defaults to the supplied options. The following options are available:
 *
 * - redis: The Redis instance we should use to store data
 * - namespace: The namespace prefix to prevent collision's.
 * - interval: Expire interval to keep the server alive in Redis
 * - timeout: Timeout for sparks who are alive.
 * - latency: Time it takes for our Redis commands to execute.
 *
 * @param {Primus} primus The Primus instance that received the plugin.
 * @param {Object} options Configuration.
 * @returns {Object} Options.
 * @api public
 */
function Metroplex(primus, options) {
  if (!(this instanceof Metroplex)) return new Metroplex(primus, options);

  options = options || {};
  primus = primus || {};

  var parsed = this.parse(primus.server);

  this.fuse();

  this.redis = options.redis || require('redis').createClient();
  this.namespace = (options.namespace || 'metroplex') +':';
  this.interval = options.interval || 5 * 60 * 1000;
  this.timeout = options.timeout || 30 * 60;
  this.latency = options.latency || 2000;
  this.leverage = new Leverage(this.redis, {
    namespace: this.namespace
  });

  if (parsed || options.address) {
    this.register(options.address || parsed);
  }
}

fuse(Metroplex, require('eventemitter3'));

/**
 * Parse our the connection URL from a given HTTP server instance or string.
 *
 * @param {Server} server HTTP or HTTPS server instance we should read address from
 * @returns {String} The address
 * @api public
 */
Metroplex.readable('parse', function parse(server) {
  if ('string' === typeof server || !server) return server || '';

  var secure = server instanceof https.Server || 'function' === typeof server.addContext
    , address = server.address ? server.address() : undefined;

  //
  // If the HTTP server isn't listening yet to a port number the result of
  // .address will be undefined. We can only get the location
  //
  if (!address) return '';

  //
  // Seriously, 0.0.0.0 is basically localhost. Get the correct address for it.
  //
  if (address.address === '0.0.0.0') {
    address.address = ip.address();
  }

  return 'http'+ (secure ? 's' : '') +'://'+ address.address +':'+ address.port;
});

/**
 * Register a new server/address in the Metroplex registry.
 *
 * @param {String|Server} address The server to add.
 * @param {Function} fn Optional callback;
 * @returns {Metroplex}
 * @api public
 */
Metroplex.readable('register', function register(address, fn) {
  var metroplex = this;

  metroplex.address = this.parse(address || metroplex.address);
  if (!metroplex.address) {
    if (fn) fn();
    return this;
  }

  metroplex.leverage.annihilate(metroplex.address, function annihilate(err) {
    if (err) {
      if (fn) return fn(err);
      return metroplex.emit('error', err);
    }

    metroplex.redis.multi()
      .setex(metroplex.namespace + metroplex.address, metroplex.interval, Date.now())
      .sadd(metroplex.namespace +'servers', metroplex.address)
    .exec(function register(err) {
      if (err) {
        if (fn) return fn(err);
        return metroplex.emit('error', err);
      }

      metroplex.emit('register', metroplex.address);
      metroplex.setInterval();

      if (fn) fn(err, metroplex.address);
    });
  });
});

/**
 * Remove a server/address from the Metroplex registry.
 *
 * @param {String|Server} address The server to remove.
 * @param {Function} fn Optional callback.
 * @returns {Metroplex}
 * @api public
 */
Metroplex.readable('unregister', function unregister(address, fn) {
  var metroplex = this;

  address = this.parse(address || metroplex.address);
  if (!metroplex.address) {
    if (fn) fn();
    return this;
  }

  metroplex.leverage.annihilate(address, function annihilate(err) {
    if (err) {
      if (fn) return fn(err);
      return metroplex.emit('error', err);
    }

    metroplex.emit('unregister', address);

    if (metroplex.timer) clearInterval(metroplex.timer);
    if (fn) fn(err, address);
  });

  return this;
});

/**
 * Add a new connection for our registered address.
 *
 * @param {Spark} spark The connection/spark from Primus.
 * @returns {Metroplex}
 * @api public
 */
Metroplex.readable('connect', function connect(spark) {
  this.redis.multi()
    .hset(this.namespace +'sparks', spark.id, this.address)
    .sadd(this.namespace + this.address +':sparks', spark.id)
  .exec();

  return this;
});

/**
 * Remove a connection for our registered address.
 *
 * @param {Spark} spark The connection/spark from Primus.
 * @returns {Metroplex}
 * @api public
 */
Metroplex.readable('disconnect', function disconnect(spark) {
  this.redis.multi()
    .hdel(this.namespace +'sparks', spark.id)
    .srem(this.namespace + this.address +':sparks', spark.id)
  .exec();

  return this;
});

/**
 * Get all current registered servers except our selfs.
 *
 * @param {Function} fn Callback
 * @returns {Metroplex}
 * @api public
 */
Metroplex.readable('servers', function servers(self, fn) {
  var metroplex = this;

  if ('boolean' !== typeof self) {
    fn = self;
    self = 0;
  }

  this.redis.smembers(this.namespace +'servers', function smembers(err, members) {
    if (self) return fn(err, members);

    fn(err, (members || []).filter(function filter(address) {
      return address !== metroplex.address;
    }));
  });

  return this;
});

/**
 * Get the server address for a given spark id.
 *
 * @param {String} id The spark id who's server address we want to retrieve.
 * @param {Function} fn Callback
 * @returns {Metroplex}
 * @api public
 */
Metroplex.readable('spark', function spark(id, fn) {
  this.redis.hget(this.namespace +'sparks', id, fn);
  return this;
});

/**
 * Get all server addresses for the given spark ids.
 *
 * @param {Array} args The spark id's we need to look up
 * @param {Function} fn Callback.
 * @returns {Metroplex}
 * @api public
 */
Metroplex.readable('sparks', function sparks(args, fn) {
  args.push(fn);
  args.shift(this.namespace +'sparks');
  this.redis.hmget.apply(this.redis, args);

  return this;
});

/**
 * We need to make sure that this server is alive, the most easy and dirty way
 * of doing this is setting an interval which bumps the expire of our
 * dedicated server key. If we go off line, the key will expire and we will be
 * K.O. The value indicates the last "ping" that we got from the node server
 * so you can see when the last update was.
 *
 * @api private
 */
Metroplex.readable('setInterval', function setIntervals() {
  if (this.timer) clearInterval(this.timer);

  var alive = this.namespace + this.address +':alive'
    , redis = this.redis
    , metroplex = this;

  this.timer = setInterval(function interval() {
    //
    // Redis expects the expire value in seconds instead of milliseconds so we
    // need to correct our interval.
    //
    redis.setex(alive, metroplex.interval / 1000, Date.now());

    metroplex.servers(function servers(err, list) {
      if (err) return metroplex.emit('error', err);

      list.forEach(function expired(address) {
        redis.get(metroplex.namespace + address, function get(err, stamp) {
          if (err || Date.now() - +stamp < metroplex.interval) return;

          metroplex.leverage.annihilate(address, function murdered(err) {
            if (err) return metroplex.emit('error', err);
          });
        });
      });
    });
  }, this.interval - this.latency);
});

//
// Expose the Metroplex library/registry/api
//
module.exports = Metroplex;
<|endoftext|>