<commit_before>//////////////////////////////////////////////////////////////////////////////
/**
 * @module geo
 */

/*jslint devel: true, forin: true, newcap: true, plusplus: true*/
/*jslint white: true, continue:true, indent: 2*/

/*global geo, ogs, inherit, $, HTMLCanvasElement, Image*/
/*global vgl, vec4, document*/
//////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////
/**
 * Create a new instance of osmLayer
 */
//////////////////////////////////////////////////////////////////////////////
geo.osmLayer = function(arg) {
  'use strict';

  if (!(this instanceof geo.osmLayer)) {
    return new geo.osmLayer(arg);
  }
  geo.featureLayer.call(this, arg);

  ////////////////////////////////////////////////////////////////////////////
  /**
   * Private member variables
   *
   * @private
   */
  ////////////////////////////////////////////////////////////////////////////
  var m_this = this,
    MAP_OSM = 0,
    MAP_MQOSM = 1,
    MAP_MQAERIAL = 2,
    MAP_NUMTYPES = 3,
    m_mapType = MAP_MQOSM,
    m_tiles = {},
    m_hiddenBinNumber = 0,
    m_visibleBinNumber = 1000,
    m_pendingNewTiles = [],
    m_pendingInactiveTiles = [],
    m_numberOfCachedTiles = 0,
    m_tileCacheSize = 100,
    m_previousZoom = null,
    m_baseUrl = 'http://otile1.mqcdn.com/tiles/1.0.0/osm/',
    s_init = this._init,
    s_update = this._update;

  if (arg && arg.baseUrl !== undefined) {
    m_baseUrl = arg.baseUrl;
  }

  ////////////////////////////////////////////////////////////////////////////
  /**
   * Get/Set tile cache size
   */
  ////////////////////////////////////////////////////////////////////////////
  this.tileCacheSize = function(val) {
    if (val === undefined) {
      return m_tileCacheSize;
    }
    m_tileCacheSize = val;
    this.modified();
  };

  ////////////////////////////////////////////////////////////////////////////
  /**
   * Transform a point or array of points in latitude-longitude space to
   * local space of the layer
   */
  ////////////////////////////////////////////////////////////////////////////
  this.toLocal = function(input) {
    var i, output = [];

    /// Now handle different data types
    if (input instanceof Array && input.length > 0) {
      output.length = input.length;

      /// Input is array of geo.latlng
      if (input[0] instanceof geo.latlng) {
        for (i = 0; i < input.length; ++i) {
          output[i] = geo.latlng(input[i]);
          output[i].lat(geo.mercator.lat2y(output[i].lat()));
        }
      } else {
        output = m_baseLayer.renderer().worldToDisplay(input).slice(0);
      }
    } else if (input instanceof geo.latlng) {
      output.push(geo.latlng(input));
      output[0].lat(geo.mercator.lat2y(output[0].lat()));
    } else {
      throw 'toLocal does not handle ' + input;
    }

    return output;
  };

  ////////////////////////////////////////////////////////////////////////////
  /**
   * Transform a point or array of points in local space to
   * latitude-longitude space
   */
  ////////////////////////////////////////////////////////////////////////////
  this.fromLocal = function(input) {
    var i, output = [];

    if (input instanceof Array && input.length > 0) {
      output.length = input.length;

      if (input[0] instanceof Object) {
        for (i = 0; i < input.length; ++i) {
          output[i] = {};
          output[i].x = input[i].x;
          output[i].y = geo.mercator.y2lat(input[i].y);
        }
      } else {
        for (i = 0; i < input.length; ++i) {
          output[i] = input[i];
          output[i + 1] = geo.mercator.y2lat(input[i + 1]);
        }
      }
    } else {
      throw 'fromLocal does not handle ' + input;
    }

    return output;
  };

  ////////////////////////////////////////////////////////////////////////////
  /**
   * Check if a tile exists in the cache
   *
   * @param zoom {number} The zoom value for the map [1-17]
   * @param x {number} X axis tile index
   * @param y {number} Y axis tile index
   */
  ////////////////////////////////////////////////////////////////////////////
  this._hasTile = function(zoom, x, y) {
    if (!m_tiles[zoom]) {
      return false;
    }
    if (!m_tiles[zoom][x]) {
      return false;
    }
    if (!m_tiles[zoom][x][y]) {
      return false;
    }
    return true;
  };

  ////////////////////////////////////////////////////////////////////////////
  /**
   * Create a new tile
   * @param x {number} X axis tile index
   * @param y {number} Y axis tile index
   */
  ////////////////////////////////////////////////////////////////////////////
  this._addTile = function(request, zoom, x, y) {
    if (!m_tiles[zoom]) {
      m_tiles[zoom] = {};
    }
    if (!m_tiles[zoom][x]) {
      m_tiles[zoom][x] = {};
    }
    if (m_tiles[zoom][x][y]) {
      return;
    }

    /// Compute corner points
    var noOfTilesX = Math.max(1, Math.pow(2, zoom)),
        noOfTilesY = Math.max(1, Math.pow(2, zoom)),
        /// Convert into mercator
        totalLatDegrees = 360.0,
        lonPerTile = 360.0 / noOfTilesX,
        latPerTile = totalLatDegrees / noOfTilesY,
        llx = -180.0 + x * lonPerTile,
        lly = -totalLatDegrees * 0.5 + y * latPerTile,
        urx = -180.0 + (x + 1) * lonPerTile,
        ury = -totalLatDegrees * 0.5 + (y + 1) * latPerTile,
        feature = null,
        tile = new Image();
        //console.log("New tile: ["+llx+" , "+lly+"] ["+urx+" , "+ury+"]");

    tile.LOADING = true;
    tile.LOADED = false;
    tile.REMOVED = false;
    tile.REMOVING = false;

    tile.crossOrigin = 'anonymous';
    tile.zoom = zoom;
    tile.index_x = x;
    tile.index_y = y;
    tile.llx = llx;
    tile.lly = lly;
    tile.urx = urx;
    tile.ury = ury;
    tile.lastused = new Date();

    // tile.src = "http://tile.openstreetmap.org/" + zoom + "/" + (x)
    //   + "/" + (Math.pow(2,zoom) - 1 - y) + ".png";
    tile.src = m_baseUrl + zoom + "/" +
      (x) + "/" + (Math.pow(2,zoom) - 1 - y) + ".jpg";

    m_tiles[zoom][x][y] = tile;
    m_pendingNewTiles.push(tile);

    ++m_numberOfCachedTiles;
    return tile;
  };

  ////////////////////////////////////////////////////////////////////////////
  /**
   * Clear tiles that are no longer required
   */
  ////////////////////////////////////////////////////////////////////////////
  this._removeTiles = function(request) {
    var i, x, y, tile, zoom, currZoom = this.map().zoom();

    if (!m_tiles) {
      return this;
    }

    if (m_previousZoom === currZoom) {
      return this;
    }
    m_previousZoom = currZoom;

    for (zoom in m_tiles) {
      if (currZoom === zoom) {
        continue;
      }
      for (x in m_tiles[zoom]) {
        for (y in m_tiles[zoom][x]) {
          tile = m_tiles[zoom][x][y];
          if (tile) {
            tile.REMOVING = true;
            m_pendingInactiveTiles.push(tile);
          }
        }
      }
    }

    setTimeout(function() {
      var tile, i;

      /// First remove the tiles if we have cached more than max cached limit
      m_pendingInactiveTiles.sort(function(a, b) {
        return a.lastused - b.lastused;
      });

      i = 0;
      /// Get rid of tiles if we have reached our threshold. However,
      /// If the tile is required for current zoom, then do nothing.
      while (m_numberOfCachedTiles > m_tileCacheSize &&
        i < m_pendingInactiveTiles.length) {
        tile = m_pendingInactiveTiles[i];
        if (tile.zoom !== m_this.map().zoom()) {
          m_this._delete(tile.feature);
          delete m_tiles[tile.zoom][tile.index_x][tile.index_y];
          m_pendingInactiveTiles.splice(i, 1);
          --m_numberOfCachedTiles;
        }
        ++i;
      }

      for (i = 0; i < m_pendingInactiveTiles.length; ++i) {
        tile = m_pendingInactiveTiles[i];
        if (tile.zoom !== m_this.map().zoom()) {
          tile.REMOVING = false;
          tile.REMOVED = true;
          tile.feature.bin(m_hiddenBinNumber);
        } else {
          tile.REMOVING = false;
          tile.REMOVED = false;
          tile.lastused = new Date();
          tile.feature.bin(m_visibleBinNumber);
        }
        tile.feature._update();
      }
      m_pendingInactiveTiles = [];
      m_this._draw();
    }, 100);

    return this;
  };

  ////////////////////////////////////////////////////////////////////////////
  /**
   * Create / delete tiles as necessary
   */
  ////////////////////////////////////////////////////////////////////////////
  this._addTiles = function(request) {
    var feature, ren = this.renderer(), node = this.node(),
        zoom = this.map().zoom(),
        /// First get corner points
        /// In display coordinates the origin is on top left corner (0, 0)
        llx = 0.0, lly = this.height(), urx = this.width(), ury = 0.0,
        temp = null, tile = null, tile1x = null, tile1y = null, tile2x = null,
        tile2y = null, invJ = null, i = 0, j = 0,
        worldPt1 = ren.displayToWorld([llx, lly])[0],
        worldPt2 = ren.displayToWorld([urx, ury])[0];

    worldPt1[0] = Math.max(worldPt1[0], -180.0);
    worldPt1[0] = Math.min(worldPt1[0],  180.0);
    worldPt1[1] = Math.max(worldPt1[1], -180.0);
    worldPt1[1] = Math.min(worldPt1[1],  180.0);

    worldPt2[0] = Math.max(worldPt2[0], -180.0);
    worldPt2[0] = Math.min(worldPt2[0],  180.0);
    worldPt2[1] = Math.max(worldPt2[1], -180.0);
    worldPt2[1] = Math.min(worldPt2[1],  180.0);

    /// Compute tilex and tiley
    tile1x = geo.mercator.long2tilex(worldPt1[0], zoom);
    tile1y = geo.mercator.lat2tiley(worldPt1[1], zoom);

    tile2x = geo.mercator.long2tilex(worldPt2[0], zoom);
    tile2y = geo.mercator.lat2tiley(worldPt2[1], zoom);

    /// Clamp tilex and tiley
    tile1x = Math.max(tile1x, 0);
    tile1x = Math.min(Math.pow(2, zoom) - 1, tile1x);
    tile1y = Math.max(tile1y, 0);
    tile1y = Math.min(Math.pow(2, zoom) - 1, tile1y);

    tile2x = Math.max(tile2x, 0);
    tile2x = Math.min(Math.pow(2, zoom) - 1, tile2x);
    tile2y = Math.max(tile2y, 0);
    tile2y = Math.min(Math.pow(2, zoom) - 1, tile2y);

    /// Check and update variables appropriately if view
    /// direction is flipped. This should not happen but
    /// just in case.
    if (tile1x > tile2x) {
      temp = tile1x;
      tile1x = tile2x;
      tile2x = temp;
    }
    if (tile2y > tile1y) {
      temp = tile1y;
      tile1x = tile2y;
      tile2y = temp;
    }

    for (i = tile1x; i <= tile2x; ++i) {
      for (j = tile2y; j <= tile1y; ++j) {
        invJ = (Math.pow(2,zoom) - 1 - j);
        if  (!m_this._hasTile(zoom, i, invJ)) {
          m_this._addTile(request, zoom, i, invJ);
        } else {
          tile = m_tiles[zoom][i][invJ];
          tile.feature.bin(m_visibleBinNumber);
          tile.lastused = new Date();
          tile.feature._update();
        }
      }
    }

    /// And now finally add them
    for (i = 0; i < m_pendingNewTiles.length; ++i) {
      tile = m_pendingNewTiles[i];

      tile.onload = function() {
        this.LOADING = false;
        this.LOADED = true;
        if ((tile.REMOVING || this.REMOVED) &&
          this.feature &&
          tile.zoom !== m_this.map().zoom()) {
          this.feature.bin(m_hiddenBinNumber);
          this.REMOVING = false;
          this.REMOVED = true;
        } else {
          this.REMOVED = false;
          this.lastused = new Date();
          this.feature.bin(m_visibleBinNumber);
        }
        this.feature._update();
        m_this._draw();
      };
      feature = this.create('planeFeature', {drawOnAsyncResourceLoad: false})
                  .origin([tile.llx, tile.lly])
                  .upperLeft([tile.llx, tile.ury])
                  .lowerRight([tile.urx, tile.lly])
                  .gcs('"EPSG:3857"')
                  .style('image', tile);
      tile.feature = feature;
    }
    m_pendingNewTiles = [];
  }

  ////////////////////////////////////////////////////////////////////////////
  /**
   * Create / delete tiles as necessary
   */
  ////////////////////////////////////////////////////////////////////////////
  this._updateTiles = function(request) {
    var zoom = m_this.map().zoom();
    /// Add tiles that are currently visible
    this._addTiles(request);

    /// Remove or hide tiles that are not visible
    m_this._removeTiles(request);

    /// Trigger draw now
    m_this._draw();

    this.updateTime().modified();
    return this;
  };

  ////////////////////////////////////////////////////////////////////////////
  /**
   * Initialize
   *
   * Do not call parent _init method as its already been executed
   */
  ////////////////////////////////////////////////////////////////////////////
  this._init = function() {
    s_init.call(this);
    this.gcs("EPSG:3857");
    return this;
  };

  ////////////////////////////////////////////////////////////////////////////
  /**
   * Update layer
   */
  ////////////////////////////////////////////////////////////////////////////
  this._update = function(request) {
    /// Update tiles (create new / delete old etc...)
    this._updateTiles(request);

    /// Now call base class update
    s_update.call(this, request);
  };

  return this;
};

inherit(geo.osmLayer, geo.featureLayer);
<commit_msg>Allow the image format for OSM tile to be set<commit_after>//////////////////////////////////////////////////////////////////////////////
/**
 * @module geo
 */

/*jslint devel: true, forin: true, newcap: true, plusplus: true*/
/*jslint white: true, continue:true, indent: 2*/

/*global geo, ogs, inherit, $, HTMLCanvasElement, Image*/
/*global vgl, vec4, document*/
//////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////
/**
 * Create a new instance of osmLayer
 */
//////////////////////////////////////////////////////////////////////////////
geo.osmLayer = function(arg) {
  'use strict';

  if (!(this instanceof geo.osmLayer)) {
    return new geo.osmLayer(arg);
  }
  geo.featureLayer.call(this, arg);

  ////////////////////////////////////////////////////////////////////////////
  /**
   * Private member variables
   *
   * @private
   */
  ////////////////////////////////////////////////////////////////////////////
  var m_this = this,
    MAP_OSM = 0,
    MAP_MQOSM = 1,
    MAP_MQAERIAL = 2,
    MAP_NUMTYPES = 3,
    m_mapType = MAP_MQOSM,
    m_tiles = {},
    m_hiddenBinNumber = 0,
    m_visibleBinNumber = 1000,
    m_pendingNewTiles = [],
    m_pendingInactiveTiles = [],
    m_numberOfCachedTiles = 0,
    m_tileCacheSize = 100,
    m_previousZoom = null,
    m_baseUrl = 'http://otile1.mqcdn.com/tiles/1.0.0/osm/',
    m_imageFormat = 'jpg',
    s_init = this._init,
    s_update = this._update;

  if (arg && arg.baseUrl !== undefined) {
    m_baseUrl = arg.baseUrl;
  }

  if (arg && arg.imageFormat !== undefined) {
    m_imageFormat = arg.imageFormat;
  }

  ////////////////////////////////////////////////////////////////////////////
  /**
   * Get/Set tile cache size
   */
  ////////////////////////////////////////////////////////////////////////////
  this.tileCacheSize = function(val) {
    if (val === undefined) {
      return m_tileCacheSize;
    }
    m_tileCacheSize = val;
    this.modified();
  };

  ////////////////////////////////////////////////////////////////////////////
  /**
   * Transform a point or array of points in latitude-longitude space to
   * local space of the layer
   */
  ////////////////////////////////////////////////////////////////////////////
  this.toLocal = function(input) {
    var i, output = [];

    /// Now handle different data types
    if (input instanceof Array && input.length > 0) {
      output.length = input.length;

      /// Input is array of geo.latlng
      if (input[0] instanceof geo.latlng) {
        for (i = 0; i < input.length; ++i) {
          output[i] = geo.latlng(input[i]);
          output[i].lat(geo.mercator.lat2y(output[i].lat()));
        }
      } else {
        output = m_baseLayer.renderer().worldToDisplay(input).slice(0);
      }
    } else if (input instanceof geo.latlng) {
      output.push(geo.latlng(input));
      output[0].lat(geo.mercator.lat2y(output[0].lat()));
    } else {
      throw 'toLocal does not handle ' + input;
    }

    return output;
  };

  ////////////////////////////////////////////////////////////////////////////
  /**
   * Transform a point or array of points in local space to
   * latitude-longitude space
   */
  ////////////////////////////////////////////////////////////////////////////
  this.fromLocal = function(input) {
    var i, output = [];

    if (input instanceof Array && input.length > 0) {
      output.length = input.length;

      if (input[0] instanceof Object) {
        for (i = 0; i < input.length; ++i) {
          output[i] = {};
          output[i].x = input[i].x;
          output[i].y = geo.mercator.y2lat(input[i].y);
        }
      } else {
        for (i = 0; i < input.length; ++i) {
          output[i] = input[i];
          output[i + 1] = geo.mercator.y2lat(input[i + 1]);
        }
      }
    } else {
      throw 'fromLocal does not handle ' + input;
    }

    return output;
  };

  ////////////////////////////////////////////////////////////////////////////
  /**
   * Check if a tile exists in the cache
   *
   * @param zoom {number} The zoom value for the map [1-17]
   * @param x {number} X axis tile index
   * @param y {number} Y axis tile index
   */
  ////////////////////////////////////////////////////////////////////////////
  this._hasTile = function(zoom, x, y) {
    if (!m_tiles[zoom]) {
      return false;
    }
    if (!m_tiles[zoom][x]) {
      return false;
    }
    if (!m_tiles[zoom][x][y]) {
      return false;
    }
    return true;
  };

  ////////////////////////////////////////////////////////////////////////////
  /**
   * Create a new tile
   * @param x {number} X axis tile index
   * @param y {number} Y axis tile index
   */
  ////////////////////////////////////////////////////////////////////////////
  this._addTile = function(request, zoom, x, y) {
    if (!m_tiles[zoom]) {
      m_tiles[zoom] = {};
    }
    if (!m_tiles[zoom][x]) {
      m_tiles[zoom][x] = {};
    }
    if (m_tiles[zoom][x][y]) {
      return;
    }

    /// Compute corner points
    var noOfTilesX = Math.max(1, Math.pow(2, zoom)),
        noOfTilesY = Math.max(1, Math.pow(2, zoom)),
        /// Convert into mercator
        totalLatDegrees = 360.0,
        lonPerTile = 360.0 / noOfTilesX,
        latPerTile = totalLatDegrees / noOfTilesY,
        llx = -180.0 + x * lonPerTile,
        lly = -totalLatDegrees * 0.5 + y * latPerTile,
        urx = -180.0 + (x + 1) * lonPerTile,
        ury = -totalLatDegrees * 0.5 + (y + 1) * latPerTile,
        feature = null,
        tile = new Image();
        //console.log("New tile: ["+llx+" , "+lly+"] ["+urx+" , "+ury+"]");

    tile.LOADING = true;
    tile.LOADED = false;
    tile.REMOVED = false;
    tile.REMOVING = false;

    tile.crossOrigin = 'anonymous';
    tile.zoom = zoom;
    tile.index_x = x;
    tile.index_y = y;
    tile.llx = llx;
    tile.lly = lly;
    tile.urx = urx;
    tile.ury = ury;
    tile.lastused = new Date();

    // tile.src = "http://tile.openstreetmap.org/" + zoom + "/" + (x)
    //   + "/" + (Math.pow(2,zoom) - 1 - y) + ".png";
    tile.src = m_baseUrl + zoom + "/" +
      (x) + "/" + (Math.pow(2,zoom) - 1 - y) + "." + m_imageFormat;

    m_tiles[zoom][x][y] = tile;
    m_pendingNewTiles.push(tile);

    ++m_numberOfCachedTiles;
    return tile;
  };

  ////////////////////////////////////////////////////////////////////////////
  /**
   * Clear tiles that are no longer required
   */
  ////////////////////////////////////////////////////////////////////////////
  this._removeTiles = function(request) {
    var i, x, y, tile, zoom, currZoom = this.map().zoom();

    if (!m_tiles) {
      return this;
    }

    if (m_previousZoom === currZoom) {
      return this;
    }
    m_previousZoom = currZoom;

    for (zoom in m_tiles) {
      if (currZoom === zoom) {
        continue;
      }
      for (x in m_tiles[zoom]) {
        for (y in m_tiles[zoom][x]) {
          tile = m_tiles[zoom][x][y];
          if (tile) {
            tile.REMOVING = true;
            m_pendingInactiveTiles.push(tile);
          }
        }
      }
    }

    setTimeout(function() {
      var tile, i;

      /// First remove the tiles if we have cached more than max cached limit
      m_pendingInactiveTiles.sort(function(a, b) {
        return a.lastused - b.lastused;
      });

      i = 0;
      /// Get rid of tiles if we have reached our threshold. However,
      /// If the tile is required for current zoom, then do nothing.
      while (m_numberOfCachedTiles > m_tileCacheSize &&
        i < m_pendingInactiveTiles.length) {
        tile = m_pendingInactiveTiles[i];
        if (tile.zoom !== m_this.map().zoom()) {
          m_this._delete(tile.feature);
          delete m_tiles[tile.zoom][tile.index_x][tile.index_y];
          m_pendingInactiveTiles.splice(i, 1);
          --m_numberOfCachedTiles;
        }
        ++i;
      }

      for (i = 0; i < m_pendingInactiveTiles.length; ++i) {
        tile = m_pendingInactiveTiles[i];
        if (tile.zoom !== m_this.map().zoom()) {
          tile.REMOVING = false;
          tile.REMOVED = true;
          tile.feature.bin(m_hiddenBinNumber);
        } else {
          tile.REMOVING = false;
          tile.REMOVED = false;
          tile.lastused = new Date();
          tile.feature.bin(m_visibleBinNumber);
        }
        tile.feature._update();
      }
      m_pendingInactiveTiles = [];
      m_this._draw();
    }, 100);

    return this;
  };

  ////////////////////////////////////////////////////////////////////////////
  /**
   * Create / delete tiles as necessary
   */
  ////////////////////////////////////////////////////////////////////////////
  this._addTiles = function(request) {
    var feature, ren = this.renderer(), node = this.node(),
        zoom = this.map().zoom(),
        /// First get corner points
        /// In display coordinates the origin is on top left corner (0, 0)
        llx = 0.0, lly = this.height(), urx = this.width(), ury = 0.0,
        temp = null, tile = null, tile1x = null, tile1y = null, tile2x = null,
        tile2y = null, invJ = null, i = 0, j = 0,
        worldPt1 = ren.displayToWorld([llx, lly])[0],
        worldPt2 = ren.displayToWorld([urx, ury])[0];

    worldPt1[0] = Math.max(worldPt1[0], -180.0);
    worldPt1[0] = Math.min(worldPt1[0],  180.0);
    worldPt1[1] = Math.max(worldPt1[1], -180.0);
    worldPt1[1] = Math.min(worldPt1[1],  180.0);

    worldPt2[0] = Math.max(worldPt2[0], -180.0);
    worldPt2[0] = Math.min(worldPt2[0],  180.0);
    worldPt2[1] = Math.max(worldPt2[1], -180.0);
    worldPt2[1] = Math.min(worldPt2[1],  180.0);

    /// Compute tilex and tiley
    tile1x = geo.mercator.long2tilex(worldPt1[0], zoom);
    tile1y = geo.mercator.lat2tiley(worldPt1[1], zoom);

    tile2x = geo.mercator.long2tilex(worldPt2[0], zoom);
    tile2y = geo.mercator.lat2tiley(worldPt2[1], zoom);

    /// Clamp tilex and tiley
    tile1x = Math.max(tile1x, 0);
    tile1x = Math.min(Math.pow(2, zoom) - 1, tile1x);
    tile1y = Math.max(tile1y, 0);
    tile1y = Math.min(Math.pow(2, zoom) - 1, tile1y);

    tile2x = Math.max(tile2x, 0);
    tile2x = Math.min(Math.pow(2, zoom) - 1, tile2x);
    tile2y = Math.max(tile2y, 0);
    tile2y = Math.min(Math.pow(2, zoom) - 1, tile2y);

    /// Check and update variables appropriately if view
    /// direction is flipped. This should not happen but
    /// just in case.
    if (tile1x > tile2x) {
      temp = tile1x;
      tile1x = tile2x;
      tile2x = temp;
    }
    if (tile2y > tile1y) {
      temp = tile1y;
      tile1x = tile2y;
      tile2y = temp;
    }

    for (i = tile1x; i <= tile2x; ++i) {
      for (j = tile2y; j <= tile1y; ++j) {
        invJ = (Math.pow(2,zoom) - 1 - j);
        if  (!m_this._hasTile(zoom, i, invJ)) {
          m_this._addTile(request, zoom, i, invJ);
        } else {
          tile = m_tiles[zoom][i][invJ];
          tile.feature.bin(m_visibleBinNumber);
          tile.lastused = new Date();
          tile.feature._update();
        }
      }
    }

    /// And now finally add them
    for (i = 0; i < m_pendingNewTiles.length; ++i) {
      tile = m_pendingNewTiles[i];

      tile.onload = function() {
        this.LOADING = false;
        this.LOADED = true;
        if ((tile.REMOVING || this.REMOVED) &&
          this.feature &&
          tile.zoom !== m_this.map().zoom()) {
          this.feature.bin(m_hiddenBinNumber);
          this.REMOVING = false;
          this.REMOVED = true;
        } else {
          this.REMOVED = false;
          this.lastused = new Date();
          this.feature.bin(m_visibleBinNumber);
        }
        this.feature._update();
        m_this._draw();
      };
      feature = this.create('planeFeature', {drawOnAsyncResourceLoad: false})
                  .origin([tile.llx, tile.lly])
                  .upperLeft([tile.llx, tile.ury])
                  .lowerRight([tile.urx, tile.lly])
                  .gcs('"EPSG:3857"')
                  .style('image', tile);
      tile.feature = feature;
    }
    m_pendingNewTiles = [];
  }

  ////////////////////////////////////////////////////////////////////////////
  /**
   * Create / delete tiles as necessary
   */
  ////////////////////////////////////////////////////////////////////////////
  this._updateTiles = function(request) {
    var zoom = m_this.map().zoom();
    /// Add tiles that are currently visible
    this._addTiles(request);

    /// Remove or hide tiles that are not visible
    m_this._removeTiles(request);

    /// Trigger draw now
    m_this._draw();

    this.updateTime().modified();
    return this;
  };

  ////////////////////////////////////////////////////////////////////////////
  /**
   * Initialize
   *
   * Do not call parent _init method as its already been executed
   */
  ////////////////////////////////////////////////////////////////////////////
  this._init = function() {
    s_init.call(this);
    this.gcs("EPSG:3857");
    return this;
  };

  ////////////////////////////////////////////////////////////////////////////
  /**
   * Update layer
   */
  ////////////////////////////////////////////////////////////////////////////
  this._update = function(request) {
    /// Update tiles (create new / delete old etc...)
    this._updateTiles(request);

    /// Now call base class update
    s_update.call(this, request);
  };

  return this;
};

inherit(geo.osmLayer, geo.featureLayer);
<|endoftext|>


<commit_before>/**
 * Imports
 */
import React from 'react';
import connectToStores from 'fluxible-addons-react/connectToStores';
import {FormattedMessage} from 'react-intl';
import {Link} from 'react-router';

// Flux
import GroupsAddStore from '../../../stores/Groups/GroupsAddStore';
import GroupsListStore from '../../../stores/Groups/GroupsListStore';
import IntlStore from '../../../stores/Application/IntlStore';
import AccountStore from '../../../stores/Account/AccountStore';
import ProductDetailsStore from '../../../stores/Products/ProductDetailsStore';

import addGroup from '../../../actions/Groups/addGroup';
import fetchGroups from '../../../actions/Groups/fetchGroups';
import updateGroup from '../../../actions/Groups/updateGroup';
import fetchProductAndCheckIfFound from '../../../actions/Products/fetchProductAndCheckIfFound';
import addToCart from '../../../actions/Cart/addToCart';

// Required components
import Button from '../../common/buttons/Button';
import Heading from '../../common/typography/Heading';
import Label from '../../common/indicators/Label';
import Modal from '../../common/modals/Modal';
import StatusIndicator from '../../common/indicators/StatusIndicator';
import Table from '../../common/tables/Table';
import Text from '../../common/typography/Text';
import GroupAddForm from './GroupAddForm';
import VerdurasProduct from './VerdurasProduct';

import { Circle } from 'rc-progress';

// Translation data for this component
import intlData from './Groups.intl';

/**
 * Component
 */
class Groups extends React.Component {

    static contextTypes = {
        executeAction: React.PropTypes.func.isRequired,
        getStore: React.PropTypes.func.isRequired,
        router: React.PropTypes.func.isRequired
    };

    static fetchData = function (context, params, query, done) {
        context.executeAction(fetchGroups, {}, done);
    };

    state = {
        product: this.context.getStore(ProductDetailsStore).getProduct(),
        addGroup: this.context.getStore(GroupsAddStore).getState(),
        groups: this.context.getStore(GroupsListStore).getGroups(),
        user: this.context.getStore(AccountStore).getAccountDetails(),
        buyers: [],
        registerModal: false,
        showThanksModal: false,
        showNewGroupModal: false,
        showGrupoCompletoModal: false,
    };

    componentDidMount() {
        require('./Groups.scss');
    }

    componentWillReceiveProps(nextProps) {

        this.setState({
            product: nextProps._product,
            addGroup: nextProps._addGroup,
            groups: nextProps._groups,
            user: nextProps._user,
            buyers: [],
            registerModal: false,
            showThanksModal: false,
            showNewGroupModal: false,
            showGrupoCompletoModal: false,
        });
    }

    //*** View Controllers ***//

    handleNewGroupClick = () => {
        this.setState({showNewGroupModal: true});
    };

    handleNewGroupCloseClick = () => {
        this.setState({showNewGroupModal: false});
    };

    handleShowThanksModalCloseClick = () => {
        this.setState({showThanksModal: false});
    };

    handleShowGrupoCompletoModalCloseClick = () => {
        this.setState({showGrupoCompletoModal: false});
    };

    handleNewGroupSubmitClick = (data) => {
        this.context.executeAction(addGroup, data);
        this.setState({showNewGroupModal: false});
    };

    handleRegisterBottom = () => {
        this.setState({registerModal: true});
    };

    handleRegiserModalCloseClick = () => {
        this.setState({registerModal: false});
    };

    handleGetOutGroupClick = (group) => {
        let index = group.buyers.indexOf(this.state.user.email);
        if (index >= 0) {
          group.buyers.splice( index, 1 );
          this.context.executeAction(updateGroup, {
              id: group.id,
              data: {
                  name: group.name,
                  tags: group.tags,
                  buyers: group.buyers
              }
          });
          this.forceUpdate();
        }
    };

    handleGetInGroupClick = (group) => {
      let user = this.state.user;

          if(group.buyers.length === 18) {
            this.setState({showGrupoCompletoModal: true});
          } else {
            group.buyers.push(user.email);
            this.context.executeAction(updateGroup, {
                id: group.id,
                data: {
                    name: group.name,
                    tags: group.tags,
                    buyers: group.buyers
                }
            });

            let payload = Object.assign({details: this.state.product}, {
                id: this.state.product.id,
                quantity: 1
            });
            this.context.executeAction(addToCart, payload);
            this.setState({addingToCart: true,showThanksModal: true});
          }
    };

    //*** Template ***//

    render() {
        let intlStore = this.context.getStore(IntlStore);
        let routeParams = {locale: this.context.getStore(IntlStore).getCurrentLocale()};
        let isAdmin = this.context.getStore(AccountStore).isAuthorized(['admin']);
        let isLogged = this.context.getStore(AccountStore).getAccountDetails();

        let newGroupModal = () => {
            if (this.state.showNewGroupModal) {
                return (
                    <Modal title={intlStore.getMessage(intlData, 'newModalTitle')}
                           onCloseClick={this.handleNewGroupCloseClick}>
                        <GroupAddForm
                            onCancelClick={this.handleNewGroupCloseClick}
                            onSubmitClick={this.handleNewGroupSubmitClick} />
                    </Modal>
                );
            }
        };

        let thanksModal = () => {
            if (this.state.showThanksModal) {
                return (
                    <Modal title={intlStore.getMessage(intlData, 'anotadoModalTitle')}
                            onCloseClick={this.handleShowThanksModalCloseClick}>

                             <FormattedMessage
                                 message={intlStore.getMessage(intlData, 'thanksModalText')}
                                 locales={intlStore.getCurrentLocale()} />

                                   <Link to="checkout" params={routeParams}>
                                     <Button type="primary">
                                         <FormattedMessage
                                             message={intlStore.getMessage(intlData, 'checkout')}
                                             locales={intlStore.getCurrentLocale()} />
                                     </Button>
                                   </Link>

                                     <Button type="primary" onClick={this.handleShowThanksModalCloseClick}>
                                         <FormattedMessage
                                             message={intlStore.getMessage(intlData, 'continueShopping')}
                                             locales={intlStore.getCurrentLocale()} />
                                     </Button>

                    </Modal>
                );
            }
        };

        let grupoCompletoModal = () => {
            if (this.state.showGrupoCompletoModal) {
                return (
                    <Modal onCloseClick={this.handleShowGrupoCompletoModalCloseClick}>

                             <FormattedMessage
                                 message={intlStore.getMessage(intlData, 'grupoCompletoModalTitle')}
                                 locales={intlStore.getCurrentLocale()} />

                                 <Button type="primary" onClick={this.handleShowGrupoCompletoModalCloseClick}>
                                    <FormattedMessage
                                         message={intlStore.getMessage(intlData, 'aceptar')}
                                         locales={intlStore.getCurrentLocale()} />
                                 </Button>

                    </Modal>
                );
            }
        };

        let registerModal = () => {
            if (this.state.registerModal) {
                return (
                    <Modal title={intlStore.getMessage(intlData, 'registerModalTitle')}
                           onCloseClick={this.handleRegiserModalCloseClick}>

                               <Link to="login" params={routeParams}>
                                 <Button type="primary">
                                     <FormattedMessage
                                         message={intlStore.getMessage(intlData, 'login')}
                                         locales={intlStore.getCurrentLocale()} />
                                 </Button>
                               </Link>

                               <Link to="register" params={routeParams}>
                                 <Button type="primary">
                                     <FormattedMessage
                                         message={intlStore.getMessage(intlData, 'register')}
                                         locales={intlStore.getCurrentLocale()} />
                                 </Button>
                               </Link>

                               <Button type="default" onClick={this.handleRegiserModalCloseClick}>
                                   <FormattedMessage
                                       message={intlStore.getMessage(intlData, 'cancel')}
                                       locales={intlStore.getCurrentLocale()} />
                               </Button>

                    </Modal>
                );
            }
        };

        return (

                  <Heading size="large">
                      <FormattedMessage
                          message={intlStore.getMessage(intlData, 'title')}
                          locales={intlStore.getCurrentLocale()} />
                  </Heading>

              {registerModal()}
              {thanksModal()}
              {grupoCompletoModal()}

<FormattedMessage
                            message={intlStore.getMessage(intlData, 'content1')}
                            locales={intlStore.getCurrentLocale()} />

                  <Heading size="small">
                    <FormattedMessage message={intlStore.getMessage(intlData, 'aclarationGroups')}
                                      locales={intlStore.getCurrentLocale()} />
                  </Heading>

              { isAdmin ?

                  {newGroupModal()}

                          <Button type="primary" onClick={this.handleNewGroupClick}>
                              <FormattedMessage
                                  message={intlStore.getMessage(intlData, 'new')}
                                  locales={intlStore.getCurrentLocale()} />
                          </Button>

                  :
                  null
              }

              {this.state.groups.length === 0 ?

                      <Text size="small">
                          <FormattedMessage message={intlStore.getMessage(intlData, 'noResults')}
                                            locales={intlStore.getCurrentLocale()} />
                      </Text>

                  :

                        {this.state.groups.map((group, idx) => {
                            return (

                                    <Text weight="bold" size="medium">
                                      <FormattedMessage
                                          message={intlStore.getMessage(group.name)}
                                          locales={intlStore.getCurrentLocale()} />
                                    </Text>

                                    <Circle percent={group.buyers.length * 5.55} strokeWidth="6" trailWidth="2"
                                                    gapDegree="45" gapPosition="bottom" strokeColor="red" initialAnimate/>

                                  <Text size="medium">

                                        {group.buyers.length} / 10

                                  </Text>
                                  { isLogged ?

                                          { group.buyers.indexOf(this.state.user.email) !== -1 ?
                                            <Button type="primary" onClick={this.handleGetOutGroupClick.bind(null, group)}>
                                                <FormattedMessage
                                                    message={intlStore.getMessage(intlData, 'desanotarse')}
                                                    locales={intlStore.getCurrentLocale()} />
                                            </Button>
                                              :
                                              <Button type="primary" onClick={this.handleGetInGroupClick.bind(null, group)}>
                                                  <FormattedMessage
                                                      message={intlStore.getMessage(intlData, 'anotarse')}
                                                      locales={intlStore.getCurrentLocale()} />
                                              </Button>
                                          }

                                      :

                                          <Button type="primary" onClick={this.handleRegisterBottom}>
                                              <FormattedMessage
                                                  message={intlStore.getMessage(intlData, 'anotarse')}
                                                  locales={intlStore.getCurrentLocale()} />
                                          </Button>

                                  }

                            );
                        })}

              }
              <VerdurasProduct productId="b7a108b9-0663-4ab3-b300-45980ffe9e63"/>

        );
    }
}

/**
 * Flux
 */
Groups = connectToStores(Groups, [GroupsAddStore, AccountStore , GroupsListStore, ProductDetailsStore], (context) => {
    return {
        _product: context.getStore(ProductDetailsStore).getProduct(),
        _addGroup: context.getStore(GroupsAddStore).getState(),
        _user: context.getStore(AccountStore).getAccountDetails(),
        _groups: context.getStore(GroupsListStore).getGroups()
    };
});

/**
 * Exports
 */
export default Groups;
<commit_msg>touches<commit_after>/**
 * Imports
 */
import React from 'react';
import connectToStores from 'fluxible-addons-react/connectToStores';
import {FormattedMessage} from 'react-intl';
import {Link} from 'react-router';

// Flux
import GroupsAddStore from '../../../stores/Groups/GroupsAddStore';
import GroupsListStore from '../../../stores/Groups/GroupsListStore';
import IntlStore from '../../../stores/Application/IntlStore';
import AccountStore from '../../../stores/Account/AccountStore';
import ProductDetailsStore from '../../../stores/Products/ProductDetailsStore';

import addGroup from '../../../actions/Groups/addGroup';
import fetchGroups from '../../../actions/Groups/fetchGroups';
import updateGroup from '../../../actions/Groups/updateGroup';
import fetchProductAndCheckIfFound from '../../../actions/Products/fetchProductAndCheckIfFound';
import addToCart from '../../../actions/Cart/addToCart';

// Required components
import Button from '../../common/buttons/Button';
import Heading from '../../common/typography/Heading';
import Label from '../../common/indicators/Label';
import Modal from '../../common/modals/Modal';
import StatusIndicator from '../../common/indicators/StatusIndicator';
import Table from '../../common/tables/Table';
import Text from '../../common/typography/Text';
import GroupAddForm from './GroupAddForm';
import VerdurasProduct from './VerdurasProduct';

import { Circle } from 'rc-progress';

// Translation data for this component
import intlData from './Groups.intl';

/**
 * Component
 */
class Groups extends React.Component {

    static contextTypes = {
        executeAction: React.PropTypes.func.isRequired,
        getStore: React.PropTypes.func.isRequired,
        router: React.PropTypes.func.isRequired
    };

    static fetchData = function (context, params, query, done) {
        context.executeAction(fetchGroups, {}, done);
    };

    state = {
        product: this.context.getStore(ProductDetailsStore).getProduct(),
        addGroup: this.context.getStore(GroupsAddStore).getState(),
        groups: this.context.getStore(GroupsListStore).getGroups(),
        user: this.context.getStore(AccountStore).getAccountDetails(),
        buyers: [],
        registerModal: false,
        showThanksModal: false,
        showNewGroupModal: false,
        showGrupoCompletoModal: false,
    };

    componentDidMount() {
        require('./Groups.scss');
    }

    componentWillReceiveProps(nextProps) {

        this.setState({
            product: nextProps._product,
            addGroup: nextProps._addGroup,
            groups: nextProps._groups,
            user: nextProps._user,
            buyers: [],
            registerModal: false,
            showThanksModal: false,
            showNewGroupModal: false,
            showGrupoCompletoModal: false,
        });
    }

    //*** View Controllers ***//

    handleNewGroupClick = () => {
        this.setState({showNewGroupModal: true});
    };

    handleNewGroupCloseClick = () => {
        this.setState({showNewGroupModal: false});
    };

    handleShowThanksModalCloseClick = () => {
        this.setState({showThanksModal: false});
    };

    handleShowGrupoCompletoModalCloseClick = () => {
        this.setState({showGrupoCompletoModal: false});
    };

    handleNewGroupSubmitClick = (data) => {
        this.context.executeAction(addGroup, data);
        this.setState({showNewGroupModal: false});
    };

    handleRegisterBottom = () => {
        this.setState({registerModal: true});
    };

    handleRegiserModalCloseClick = () => {
        this.setState({registerModal: false});
    };

    handleGetOutGroupClick = (group) => {
        let index = group.buyers.indexOf(this.state.user.email);
        if (index >= 0) {
          group.buyers.splice( index, 1 );
          this.context.executeAction(updateGroup, {
              id: group.id,
              data: {
                  name: group.name,
                  tags: group.tags,
                  buyers: group.buyers
              }
          });
          this.forceUpdate();
        }
    };

    handleGetInGroupClick = (group) => {
      let user = this.state.user;

          if(group.buyers.length === 18) {
            this.setState({showGrupoCompletoModal: true});
          } else {
            group.buyers.push(user.email);
            this.context.executeAction(updateGroup, {
                id: group.id,
                data: {
                    name: group.name,
                    tags: group.tags,
                    buyers: group.buyers
                }
            });

            let payload = Object.assign({details: this.state.product}, {
                id: this.state.product.id,
                quantity: 1
            });
            this.context.executeAction(addToCart, payload);
            this.setState({addingToCart: true,showThanksModal: true});
          }
    };

    //*** Template ***//

    render() {
        let intlStore = this.context.getStore(IntlStore);
        let routeParams = {locale: this.context.getStore(IntlStore).getCurrentLocale()};
        let isAdmin = this.context.getStore(AccountStore).isAuthorized(['admin']);
        let isLogged = this.context.getStore(AccountStore).getAccountDetails();

        let newGroupModal = () => {
            if (this.state.showNewGroupModal) {
                return (
                    <Modal title={intlStore.getMessage(intlData, 'newModalTitle')}
                           onCloseClick={this.handleNewGroupCloseClick}>
                        <GroupAddForm
                            onCancelClick={this.handleNewGroupCloseClick}
                            onSubmitClick={this.handleNewGroupSubmitClick} />
                    </Modal>
                );
            }
        };

        let thanksModal = () => {
            if (this.state.showThanksModal) {
                return (
                    <Modal title={intlStore.getMessage(intlData, 'anotadoModalTitle')}
                            onCloseClick={this.handleShowThanksModalCloseClick}>

                             <FormattedMessage
                                 message={intlStore.getMessage(intlData, 'thanksModalText')}
                                 locales={intlStore.getCurrentLocale()} />

                                   <Link to="checkout" params={routeParams}>
                                     <Button type="primary">
                                         <FormattedMessage
                                             message={intlStore.getMessage(intlData, 'checkout')}
                                             locales={intlStore.getCurrentLocale()} />
                                     </Button>
                                   </Link>

                                     <Button type="primary" onClick={this.handleShowThanksModalCloseClick}>
                                         <FormattedMessage
                                             message={intlStore.getMessage(intlData, 'continueShopping')}
                                             locales={intlStore.getCurrentLocale()} />
                                     </Button>

                    </Modal>
                );
            }
        };

        let grupoCompletoModal = () => {
            if (this.state.showGrupoCompletoModal) {
                return (
                    <Modal onCloseClick={this.handleShowGrupoCompletoModalCloseClick}>

                             <FormattedMessage
                                 message={intlStore.getMessage(intlData, 'grupoCompletoModalTitle')}
                                 locales={intlStore.getCurrentLocale()} />

                                 <Button type="primary" onClick={this.handleShowGrupoCompletoModalCloseClick}>
                                    <FormattedMessage
                                         message={intlStore.getMessage(intlData, 'aceptar')}
                                         locales={intlStore.getCurrentLocale()} />
                                 </Button>

                    </Modal>
                );
            }
        };

        let registerModal = () => {
            if (this.state.registerModal) {
                return (
                    <Modal title={intlStore.getMessage(intlData, 'registerModalTitle')}
                           onCloseClick={this.handleRegiserModalCloseClick}>

                               <Link to="login" params={routeParams}>
                                 <Button type="primary">
                                     <FormattedMessage
                                         message={intlStore.getMessage(intlData, 'login')}
                                         locales={intlStore.getCurrentLocale()} />
                                 </Button>
                               </Link>

                               <Link to="register" params={routeParams}>
                                 <Button type="primary">
                                     <FormattedMessage
                                         message={intlStore.getMessage(intlData, 'register')}
                                         locales={intlStore.getCurrentLocale()} />
                                 </Button>
                               </Link>

                               <Button type="default" onClick={this.handleRegiserModalCloseClick}>
                                   <FormattedMessage
                                       message={intlStore.getMessage(intlData, 'cancel')}
                                       locales={intlStore.getCurrentLocale()} />
                               </Button>

                    </Modal>
                );
            }
        };

        return (

                  <Heading size="large">
                      <FormattedMessage
                          message={intlStore.getMessage(intlData, 'title')}
                          locales={intlStore.getCurrentLocale()} />
                  </Heading>

              {registerModal()}
              {thanksModal()}
              {grupoCompletoModal()}

<FormattedMessage
                            message={intlStore.getMessage(intlData, 'content1')}
                            locales={intlStore.getCurrentLocale()} />

                <VerdurasProduct productId="b7a108b9-0663-4ab3-b300-45980ffe9e63"/>

                  <Heading size="small">
                    <FormattedMessage message={intlStore.getMessage(intlData, 'aclarationGroups')}
                                      locales={intlStore.getCurrentLocale()} />
                  </Heading>

              { isAdmin ?

                  {newGroupModal()}

                          <Button type="primary" onClick={this.handleNewGroupClick}>
                              <FormattedMessage
                                  message={intlStore.getMessage(intlData, 'new')}
                                  locales={intlStore.getCurrentLocale()} />
                          </Button>

                  :
                  null
              }

              {this.state.groups.length === 0 ?

                      <Text size="small">
                          <FormattedMessage message={intlStore.getMessage(intlData, 'noResults')}
                                            locales={intlStore.getCurrentLocale()} />
                      </Text>

                  :

                        {this.state.groups.map((group, idx) => {
                            return (

                                    <Text weight="bold" size="medium">
                                      <FormattedMessage
                                          message={intlStore.getMessage(group.name)}
                                          locales={intlStore.getCurrentLocale()} />
                                    </Text>

                                    <Circle percent={group.buyers.length * 5.55} strokeWidth="6" trailWidth="2"
                                                    gapDegree="45" gapPosition="bottom" strokeColor="red" initialAnimate/>

                                  <Text size="medium">

                                        {group.buyers.length} / 10

                                  </Text>
                                  { isLogged ?

                                          { group.buyers.indexOf(this.state.user.email) !== -1 ?
                                            <Button type="primary" onClick={this.handleGetOutGroupClick.bind(null, group)}>
                                                <FormattedMessage
                                                    message={intlStore.getMessage(intlData, 'desanotarse')}
                                                    locales={intlStore.getCurrentLocale()} />
                                            </Button>
                                              :
                                              <Button type="primary" onClick={this.handleGetInGroupClick.bind(null, group)}>
                                                  <FormattedMessage
                                                      message={intlStore.getMessage(intlData, 'anotarse')}
                                                      locales={intlStore.getCurrentLocale()} />
                                              </Button>
                                          }

                                      :

                                          <Button type="primary" onClick={this.handleRegisterBottom}>
                                              <FormattedMessage
                                                  message={intlStore.getMessage(intlData, 'anotarse')}
                                                  locales={intlStore.getCurrentLocale()} />
                                          </Button>

                                  }

                            );
                        })}

              }

        );
    }
}

/**
 * Flux
 */
Groups = connectToStores(Groups, [GroupsAddStore, AccountStore , GroupsListStore, ProductDetailsStore], (context) => {
    return {
        _product: context.getStore(ProductDetailsStore).getProduct(),
        _addGroup: context.getStore(GroupsAddStore).getState(),
        _user: context.getStore(AccountStore).getAccountDetails(),
        _groups: context.getStore(GroupsListStore).getGroups()
    };
});

/**
 * Exports
 */
export default Groups;
<|endoftext|>


<commit_before>(function(window, document, undefined) {
    window.onload = init;
    function init() {

        //create an empty map
        var map = new Array(960);
        for(var i = 0; i < 960; i++) {
            map[i] = new Array(540);
        }

        //get the canvas
        var canvas = document.getElementById("mapcanvas");
        var c = canvas.getContext("2d");

        function ncount(i,j) {
            var i1 = i+1;
            var i2 = i-1;
            var j1 = j+1;
            var j2 = j-1;
            var neighbors = 0;
            if(i1 < 960 && i2 >=0 && j1 < 540 && j2 >=0){
                if(map[i1][j1] == 1){
                    neighbors++;
                }
                if(map[i][j1] == 1){
                    neighbors++;
                }
                if(map[i2][j1] == 1){
                    neighbors++;
                }
                if(map[i1][j] == 1){
                    neighbors++;
                }
                if(map[i2][j] == 1){
                    neighbors++;
                }
                if(map[i1][j2] == 1){
                    neighbors++;
                }
                if(map[i][j2] == 1){
                    neighbors++;
                }
                if(map[i2][j2] == 1){
                    neighbors++;
                }
            }
            return neighbors;
        }

        //when we click, assign values and then paint
        document.getElementById("startbtn").onclick = paint;
        var it = 1;
        function paint() {
            if(it == 1){
                //fill the values
                for(var i = 0; i< 960; i++) {
                    for(var j = 0; j < 540; j++) {
                        if(Math.random() < .45){
                            map[i][j] = 1;
                        } else {
                            map[i][j] = 0;
                        }
                    }
                }
            } else {
                for(var i = 0; i< 960; i++) {
                    for(var j = 0; j < 540; j++){
                        var nc = ncount(i,j);
                        switch(nc){
                            case 4:
                                break;
                            case 5:
                                map[i][j] = 1;
                                break;
                            case 6:
                                map[i][j] = 1;
                                break;
                            case 7:
                                map[i][j] = 1;
                                break;
                            case 8:
                                map[i][j] = 1;
                                break;
                            default:
                                map[i][j] = 0;
                        }
                    }
                }
            }

            //paint the map
            for(var i = 0; i < 960; i++) {
                for(var j = 0; j< 540; j++){
                    if(map[i][j] == 1){
                        c.fillStyle = '#87CEEB';
                        c.fillRect(i,j,1,1);
                    }
                }
            }
            it++;
            document.getElementById("iter").innerHTML = it;
        }
    }
})(window, document, undefined);
<commit_msg>Update script.js<commit_after>(function(window, document, undefined) {
    window.onload = init;
    function init() {

        //create an empty map
        var map = new Array(960);
        for(var i = 0; i < 960; i++) {
            map[i] = new Array(540);
        }

        //get the canvas
        var canvas = document.getElementById("mapcanvas");
        var c = canvas.getContext("2d");

        function ncount(i,j) {
            var i1 = i+1;
            var i2 = i-1;
            var j1 = j+1;
            var j2 = j-1;
            var neighbors = 0;
            if(i1 < 960 && i2 >=0 && j1 < 540 && j2 >=0){
                if(map[i1][j1] == 1){
                    neighbors++;
                }
                if(map[i][j1] == 1){
                    neighbors++;
                }
                if(map[i2][j1] == 1){
                    neighbors++;
                }
                if(map[i1][j] == 1){
                    neighbors++;
                }
                if(map[i2][j] == 1){
                    neighbors++;
                }
                if(map[i1][j2] == 1){
                    neighbors++;
                }
                if(map[i][j2] == 1){
                    neighbors++;
                }
                if(map[i2][j2] == 1){
                    neighbors++;
                }
            }
            return neighbors;
        }

        //when we click, assign values and then paint
        document.getElementById("startbtn").onclick = paint;
        var it = 1;
        function paint() {
            if(it == 1){
                //fill the values
                for(var i = 0; i< 960; i++) {
                    for(var j = 0; j < 540; j++) {
                        if(Math.random() < .45){
                            map[i][j] = 1;
                        } else {
                            map[i][j] = 0;
                        }
                    }
                }
            } else {
                for(var i = 0; i< 960; i++) {
                    for(var j = 0; j < 540; j++){
                        var nc = ncount(i,j);
                        switch(nc){
                            case 4:
                                break;
                            case 5:
                                break;
                            case 6:
                                break;
                            case 7:
                                break;
                            case 8:
                                break;
                            default:
                                map[i][j] = 0;
                        }
                    }
                }
            }

            //paint the map
            for(var i = 0; i < 960; i++) {
                for(var j = 0; j< 540; j++){
                    if(map[i][j] == 1){
                        c.fillStyle = '#87CEEB';
                        c.fillRect(i,j,1,1);
                    }
                }
            }
            it++;
            document.getElementById("iter").innerHTML = it;
        }
    }
})(window, document, undefined);
<|endoftext|>


<commit_before><commit_msg>rp fixes<commit_after><|endoftext|>


<commit_before>import {
  dummyModels,
  createStore
} from 'tests/test-helper';

import { Promise } from 'rsvp';
const { Planet, Moon, Star } = dummyModels;

module('Integration - Model', function(hooks) {
  let store;

  hooks.beforeEach(function() {
    const models = { planet: Planet, moon: Moon, star: Star };
    store = createStore({ models });
  });

  hooks.afterEach(function() {
    store = null;
  });

  test('add new model', function(assert) {
    Ember.run(() => {
      const done = assert.async();

      Promise.all([
        store.addRecord({type: 'star', name: 'The Sun'}),
        store.addRecord({type: 'moon', name: 'Callisto'}),
      ])
      .then(([theSun, callisto]) => {
        store
          .addRecord({type: 'planet', galaxyAlias: 'planet:jupiter', name: 'Jupiter', star: theSun, moons: [callisto]})
          .then(record => {
            assert.ok(record.get('id'), 'assigned id');
            assert.equal(record.get('name'), 'Jupiter', 'assigned specified attribute');
            assert.equal(record.get('atmosphere'), false, 'assigned default value for unspecified attribute');
            assert.equal(record.get('galaxyAlias'), 'planet:jupiter', 'assigned secondary key');
            assert.equal(record.get('star'), theSun, 'assigned hasOne');
            assert.deepEqual(record.get('moons.firstObject'), callisto, 'assigned hasMany');
            done();
          });
      });
    });
  });

  test('remove model', function(assert) {
    Ember.run(() => {
      const done = assert.async();
      const cache = store.get('cache');

      store
        .addRecord({type: 'star', name: 'The Sun'})
        .tap(record => record.remove())
        .then(record => {
          assert.ok(!cache.retrieve(['star', record.get('id')]));
          assert.ok(record.get('disconnected'), 'record has been disconnected from store');
          assert.throws(() => record.get('name'), Ember.Error, 'record has been removed from Store');
        })
        .then(done);
    });
  });

  test('add to hasMany', function(assert) {
    Ember.run(() => {
      const done = assert.async();

      Promise.all([
        store.addRecord({type: 'planet', name: 'Jupiter'}),
        store.addRecord({type: 'moon', name: 'Callisto'})
      ])
      .tap(([jupiter, callisto]) => {
        jupiter.get('moons').pushObject(callisto);
        return store;
      })
      .then(([jupiter, callisto]) => {
        assert.ok(jupiter.get('moons').contains(callisto), 'added record to hasMany');
        assert.equal(callisto.get('planet'), jupiter, 'updated inverse');
        done();
      });
    });
  });

  test('remove from hasMany', function(assert) {
    Ember.run(() => {
      const done = assert.async();

      Promise.all([
        store.addRecord({type: 'planet', name: 'Jupiter'}),
        store.addRecord({type: 'moon', name: 'Callisto'})
      ])
      .tap(([jupiter, callisto]) => store.addToHasMany(jupiter, 'moons', callisto))
      .tap(([jupiter, callisto]) => {
        jupiter.get('moons').removeObject(callisto);
        return store;
      })
      .then(([jupiter, callisto]) => {
        assert.ok(!jupiter.get('moons').contains(callisto), 'removed record from hasMany');
        assert.ok(!callisto.get('planet'), 'updated inverse');
        done();
      });
    });
  });

  test('replace hasOne with record', function(assert) {
    Ember.run(() => {
      const done = assert.async();

      Promise.all([
        store.addRecord({type: 'planet', name: 'Jupiter'}),
        store.addRecord({type: 'moon', name: 'Callisto'})
      ])
      .tap(([jupiter, callisto]) => {
        callisto.set('planet', jupiter);
        return store;
      })
      .then(([jupiter, callisto]) => {
        assert.equal(callisto.get('planet'), jupiter, 'replaced hasOne with record');
        assert.ok(jupiter.get('moons').contains(callisto), 'updated inverse');
        done();
      });
    });
  });

  test('replace hasOne with null', function(assert) {
    Ember.run(() => {
      const done = assert.async();

      Promise.all([
        store.addRecord({type: 'planet', name: 'Jupiter'}),
        store.addRecord({type: 'moon', name: 'Callisto'})
      ])
      .tap(([jupiter, callisto]) => store.replaceHasOne(callisto, 'planet', jupiter))
      .tap(([jupiter, callisto]) => {
        callisto.set('planet', null);
        return store;
      })
      .then(([jupiter, callisto]) => {
        assert.equal(callisto.get('planet'), null, 'replaced hasOne with null');
        assert.ok(!jupiter.get('moons').contains(callisto), 'removed from inverse hasMany');
        done();
      });
    });
  });

  test('replace attribute on model', function(assert) {
    Ember.run(() => {
      const done = assert.async();

      store
        .addRecord({type: 'planet', name: 'Jupiter'})
        .tap(record => record.set('name', 'Jupiter2'))
        .then(record => assert.equal(record.get('name'), 'Jupiter2'))
        .then(done);
    });
  });

  test('replace key', function(assert) {
    Ember.run(() => {
      const done = assert.async();

      store
        .addRecord({type: 'planet', name: 'Jupiter', galaxyAlias: 'planet:jupiter'})
        .tap(record => record.set('galaxyAlias', 'planet:joopiter'))
        .then(record => assert.equal(record.get('galaxyAlias'), 'planet:joopiter'))
        .then(done);
    });
  });

  test('destroy model', function(assert) {
    Ember.run(() => {
      const done = assert.async();
      const cache = store.get('cache');

      store
        .addRecord({type: 'planet', name: 'Jupiter'})
        .tap(record => record.destroy())
        .then(record => {
          const identifier = record.getProperties('type', 'id');
          assert.ok(!cache.get('_identityMap').contains(identifier), 'removed from identity map');
        })
        .then(done);
    });
  });
});
<commit_msg>Skip hasOne and hasMany assertions when adding record<commit_after>import {
  dummyModels,
  createStore
} from 'tests/test-helper';

import { Promise } from 'rsvp';
const { Planet, Moon, Star } = dummyModels;

module('Integration - Model', function(hooks) {
  let store;

  hooks.beforeEach(function() {
    const models = { planet: Planet, moon: Moon, star: Star };
    store = createStore({ models });
  });

  hooks.afterEach(function() {
    store = null;
  });

  test('add new model', function(assert) {
    Ember.run(() => {
      const done = assert.async();

      Promise.all([
        store.addRecord({type: 'star', name: 'The Sun'}),
        store.addRecord({type: 'moon', name: 'Callisto'}),
      ])
      .then(([theSun, callisto]) => {
        store
          .addRecord({type: 'planet', galaxyAlias: 'planet:jupiter', name: 'Jupiter', star: theSun, moons: [callisto]})
          .then(record => {
            assert.ok(record.get('id'), 'assigned id');
            assert.equal(record.get('name'), 'Jupiter', 'assigned specified attribute');
            assert.equal(record.get('atmosphere'), false, 'assigned default value for unspecified attribute');
            assert.equal(record.get('galaxyAlias'), 'planet:jupiter', 'assigned secondary key');
            // assert.equal(record.get('star'), theSun, 'assigned hasOne');
            // assert.deepEqual(record.get('moons.firstObject'), callisto, 'assigned hasMany');
            done();
          });
      });
    });
  });

  test('remove model', function(assert) {
    Ember.run(() => {
      const done = assert.async();
      const cache = store.get('cache');

      store
        .addRecord({type: 'star', name: 'The Sun'})
        .tap(record => record.remove())
        .then(record => {
          assert.ok(!cache.retrieve(['star', record.get('id')]));
          assert.ok(record.get('disconnected'), 'record has been disconnected from store');
          assert.throws(() => record.get('name'), Ember.Error, 'record has been removed from Store');
        })
        .then(done);
    });
  });

  test('add to hasMany', function(assert) {
    Ember.run(() => {
      const done = assert.async();

      Promise.all([
        store.addRecord({type: 'planet', name: 'Jupiter'}),
        store.addRecord({type: 'moon', name: 'Callisto'})
      ])
      .tap(([jupiter, callisto]) => {
        jupiter.get('moons').pushObject(callisto);
        return store;
      })
      .then(([jupiter, callisto]) => {
        assert.ok(jupiter.get('moons').contains(callisto), 'added record to hasMany');
        assert.equal(callisto.get('planet'), jupiter, 'updated inverse');
        done();
      });
    });
  });

  test('remove from hasMany', function(assert) {
    Ember.run(() => {
      const done = assert.async();

      Promise.all([
        store.addRecord({type: 'planet', name: 'Jupiter'}),
        store.addRecord({type: 'moon', name: 'Callisto'})
      ])
      .tap(([jupiter, callisto]) => store.addToHasMany(jupiter, 'moons', callisto))
      .tap(([jupiter, callisto]) => {
        jupiter.get('moons').removeObject(callisto);
        return store;
      })
      .then(([jupiter, callisto]) => {
        assert.ok(!jupiter.get('moons').contains(callisto), 'removed record from hasMany');
        assert.ok(!callisto.get('planet'), 'updated inverse');
        done();
      });
    });
  });

  test('replace hasOne with record', function(assert) {
    Ember.run(() => {
      const done = assert.async();

      Promise.all([
        store.addRecord({type: 'planet', name: 'Jupiter'}),
        store.addRecord({type: 'moon', name: 'Callisto'})
      ])
      .tap(([jupiter, callisto]) => {
        callisto.set('planet', jupiter);
        return store;
      })
      .then(([jupiter, callisto]) => {
        assert.equal(callisto.get('planet'), jupiter, 'replaced hasOne with record');
        assert.ok(jupiter.get('moons').contains(callisto), 'updated inverse');
        done();
      });
    });
  });

  test('replace hasOne with null', function(assert) {
    Ember.run(() => {
      const done = assert.async();

      Promise.all([
        store.addRecord({type: 'planet', name: 'Jupiter'}),
        store.addRecord({type: 'moon', name: 'Callisto'})
      ])
      .tap(([jupiter, callisto]) => store.replaceHasOne(callisto, 'planet', jupiter))
      .tap(([jupiter, callisto]) => {
        callisto.set('planet', null);
        return store;
      })
      .then(([jupiter, callisto]) => {
        assert.equal(callisto.get('planet'), null, 'replaced hasOne with null');
        assert.ok(!jupiter.get('moons').contains(callisto), 'removed from inverse hasMany');
        done();
      });
    });
  });

  test('replace attribute on model', function(assert) {
    Ember.run(() => {
      const done = assert.async();

      store
        .addRecord({type: 'planet', name: 'Jupiter'})
        .tap(record => record.set('name', 'Jupiter2'))
        .then(record => assert.equal(record.get('name'), 'Jupiter2'))
        .then(done);
    });
  });

  test('replace key', function(assert) {
    Ember.run(() => {
      const done = assert.async();

      store
        .addRecord({type: 'planet', name: 'Jupiter', galaxyAlias: 'planet:jupiter'})
        .tap(record => record.set('galaxyAlias', 'planet:joopiter'))
        .then(record => assert.equal(record.get('galaxyAlias'), 'planet:joopiter'))
        .then(done);
    });
  });

  test('destroy model', function(assert) {
    Ember.run(() => {
      const done = assert.async();
      const cache = store.get('cache');

      store
        .addRecord({type: 'planet', name: 'Jupiter'})
        .tap(record => record.destroy())
        .then(record => {
          const identifier = record.getProperties('type', 'id');
          assert.ok(!cache.get('_identityMap').contains(identifier), 'removed from identity map');
        })
        .then(done);
    });
  });
});
<|endoftext|>


<commit_before>module.exports = function(context) {
    d3.select(window).on('unload', function() {
        if (context.data.get('type') === 'local' && context.data.hasFeatures()) {
            context.storage.set('recover', context.data.all());
        }
    });

    if (location.hash !== '#new') {
        var rec = context.storage.get('recover');
        if (rec && confirm('recover your map from the last time you edited?')) {
            context.data.set(rec);
        } else {
            context.storage.remove('recover');
        }
    }
};
<commit_msg>Kill recovery when you switch from local<commit_after>module.exports = function(context) {

    d3.select(window).on('unload', onunload);
    context.dispatch.on('change', onchange);

    if (location.hash !== '#new') {
        var rec = context.storage.get('recover');
        if (rec && confirm('recover your map from the last time you edited?')) {
            context.data.set(rec);
        } else {
            context.storage.remove('recover');
        }
    }

    function onunload() {
        if (context.data.get('type') === 'local' && context.data.hasFeatures()) {
            context.storage.set('recover', context.data.all());
        } else {
            context.storage.remove('recover');
        }
    }

    function onchange() {
        if (context.data.get('type') !== 'local') {
            context.storage.remove('recover');
        }
    }
};
<|endoftext|>


<commit_before> var uuidv4 = require('uuid/v4'),
     aws = require('aws-sdk'),
     express = require('express');

function checkTrailingSlash(path) {
    if (path && path[path.length-1] != '/') {
        path += '/';
    }
    return path;
}

function S3Router(options) {

    var S3_BUCKET = options.bucket,
        getFileKeyDir = options.getFileKeyDir || function() { return ""; };

    if (!S3_BUCKET) {
        throw new Error("S3_BUCKET is required.");
    }

    var s3Options = {};
    if (options.region) {
      s3Options.region = options.region;
    }
    if (options.signatureVersion) {
        s3Options.signatureVersion = options.signatureVersion;
    }
    if (options.uniquePrefix === undefined) {
        options.uniquePrefix = true;
    }

    var router = express.Router();

    /**
     * Redirects image requests with a temporary signed URL, giving access
     * to GET an upload.
     */
    function tempRedirect(req, res) {
        var params = {
            Bucket: S3_BUCKET,
            Key: checkTrailingSlash(getFileKeyDir(req)) + req.params[0]
        };
        var s3 = new aws.S3(s3Options);
        s3.getSignedUrl('getObject', params, function(err, url) {
            res.redirect(url);
        });
    };

    /**
     * Image specific route.
     */
    router.get(/\/img\/(.*)/, function(req, res) {
        return tempRedirect(req, res);
    });

    /**
     * Other file type(s) route.
     */
    router.get(/\/uploads\/(.*)/, function(req, res) {
        return tempRedirect(req, res);
    });

    /**
     * Returns an object with `signedUrl` and `publicUrl` properties that
     * give temporary access to PUT an object in an S3 bucket.
     */
    router.get('/sign', function(req, res) {
        var filename = (options.uniquePrefix ? uuidv4() + "_" : "") + req.query.objectName;
        var mimeType = req.query.contentType;
        var fileKey = checkTrailingSlash(getFileKeyDir(req)) + filename;
        // Set any custom headers
        if (options.headers) {
          res.set(options.headers);
        }

        var s3 = new aws.S3(s3Options);
        var params = {
            Bucket: S3_BUCKET,
            Key: fileKey,
            Expires: 60,
            ContentType: mimeType,
            ACL: options.ACL || 'private'
        };
        s3.getSignedUrl('putObject', params, function(err, data) {
            if (err) {
                console.log(err);
                return res.send(500, "Cannot create S3 signed URL");
            }
            res.json({
                signedUrl: data,
                publicUrl: '/s3/uploads/' + filename,
                filename: filename,
                fileKey: fileKey,
            });
        });
    });

    return router;
}

module.exports = S3Router;
<commit_msg>Add optional paramter to s3 router function to use middleware on signing related routes<commit_after> var uuidv4 = require('uuid/v4'),
     aws = require('aws-sdk'),
     express = require('express');

function checkTrailingSlash(path) {
    if (path && path[path.length-1] != '/') {
        path += '/';
    }
    return path;
}

function S3Router(options, middleware) {

    if (!middleware) {
        middleware = [];
    }

    var S3_BUCKET = options.bucket,
        getFileKeyDir = options.getFileKeyDir || function() { return ""; };

    if (!S3_BUCKET) {
        throw new Error("S3_BUCKET is required.");
    }

    var s3Options = {};
    if (options.region) {
      s3Options.region = options.region;
    }
    if (options.signatureVersion) {
        s3Options.signatureVersion = options.signatureVersion;
    }
    if (options.uniquePrefix === undefined) {
        options.uniquePrefix = true;
    }

    var router = express.Router();

    /**
     * Redirects image requests with a temporary signed URL, giving access
     * to GET an upload.
     */
    function tempRedirect(req, res) {
        var params = {
            Bucket: S3_BUCKET,
            Key: checkTrailingSlash(getFileKeyDir(req)) + req.params[0]
        };
        var s3 = new aws.S3(s3Options);
        s3.getSignedUrl('getObject', params, function(err, url) {
            res.redirect(url);
        });
    };

    /**
     * Image specific route.
     */
    router.get(/\/img\/(.*)/, middleware, function(req, res) {
        return tempRedirect(req, res);
    });

    /**
     * Other file type(s) route.
     */
    router.get(/\/uploads\/(.*)/, middleware, function(req, res) {
        return tempRedirect(req, res);
    });

    /**
     * Returns an object with `signedUrl` and `publicUrl` properties that
     * give temporary access to PUT an object in an S3 bucket.
     */
    router.get('/sign', middleware, function(req, res) {
        var filename = (options.uniquePrefix ? uuidv4() + "_" : "") + req.query.objectName;
        var mimeType = req.query.contentType;
        var fileKey = checkTrailingSlash(getFileKeyDir(req)) + filename;
        // Set any custom headers
        if (options.headers) {
          res.set(options.headers);
        }

        var s3 = new aws.S3(s3Options);
        var params = {
            Bucket: S3_BUCKET,
            Key: fileKey,
            Expires: 60,
            ContentType: mimeType,
            ACL: options.ACL || 'private'
        };
        s3.getSignedUrl('putObject', params, function(err, data) {
            if (err) {
                console.log(err);
                return res.send(500, "Cannot create S3 signed URL");
            }
            res.json({
                signedUrl: data,
                publicUrl: '/s3/uploads/' + filename,
                filename: filename,
                fileKey: fileKey,
            });
        });
    });

    return router;
}

module.exports = S3Router;
<|endoftext|>


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

const child_process = require('child_process');
const path = require('path');

const currentPath = path.resolve(path.relative(__dirname, process.cwd()));
console.log('path: ', currentPath);

const result = child_process
  .execSync('git diff --name-only origin/master... | cat')
  .toString();

if (result) {
  console.log(result);

  const dirs = result
    .split('\n')
    .filter(file => file)
    .map(file => path.resolve(path.dirname(file)));

  for (const dir of dirs) {
    if (dir.startsWith(currentPath)) {
      process.exit(0);
    }
  }
}

process.exit(1);
<commit_msg>simplify code<commit_after>#!/usr/bin/env node

const child_process = require('child_process');
const path = require('path');

const currentPath = path.resolve(path.relative(__dirname, process.cwd()));
console.log('path: ', currentPath);

const result = child_process
  .execSync('git diff --name-only origin/master... | cat')
  .toString();

if (result) {
  console.log(result);

  const dirs = result.split('\n').filter(file => file);

  for (const dir of dirs) {
    if (dir.startsWith(currentPath)) {
      process.exit(0);
    }
  }
}

process.exit(1);
<|endoftext|>