<commit_before>/*  Copyright (c) 2014 Iain Hamilton

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE. */

define([], function() {
  return function () {

    var mapLayers;

    var mapWidth;
    var mapHeight;
    var tileWidth;
    var tileHeight;
    var screenWidth;
    var screenHeight;

    var mapOffsetX;
    var mapOffsetY;

    var curZoom;
    var startX = 0;
    var startY = 0;
    var focusX = 0;
    var focusY = 0;

    var isometric = false;

    function _setup(layers, mapW, mapH, tileW, tileH, screenW, screenH, curZ) {
      mapLayers = layers;
      mapWidth = mapW;
      mapHeight = mapH;
      tileWidth = tileW;
      tileHeight = tileH;
      curZoom = curZ || 1;
      screenWidth = screenW;
      screenHeight = screenH;
      return {
        startX: startX,
        startY: startY,
        pinFocusX: focusX,
        pinFocusY: focusY
      };
    }

    function _getXYCoords(x, y) {
      var positionY, positionX;
      if (!isometric) {
        positionY = Math.round((y - (tileHeight * curZoom) / 2)/ (tileHeight * curZoom));
        positionX = Math.round((x - (tileWidth * curZoom) / 2)/ (tileWidth * curZoom));
      }
      else {
        positionY = (2 * (y - mapOffsetY) - x + mapOffsetX) / 2;
        positionX = x + positionY - mapOffsetX - (tileHeight * curZoom);
        positionY = Math.round(positionY / (tileHeight * curZoom));
        positionX = Math.round(positionX / (tileHeight * curZoom));
      }
      return {x: positionX, y: positionY};
    }

    function _setFocus(posX, posY, rangeX, rangeY) {
      var xyMapOffset;
      var i;
      startX = posX - screenWidth / 2;
      startY = posY - screenHeight / 2;

      if (screenHeight * tileHeight > mapHeight) {
        for (i = 0; i < mapLayers.length; i++) {
          mapLayers[i].setOffset(null, Math.floor(screenHeight * tileHeight / 2 - mapHeight / 2));
        }
      }
      else {
        for (i = 0; i < mapLayers.length; i++) {
          if (startY < 0) {
            mapLayers[i].setOffset(null, Math.floor(-tileHeight * posY + (posY * tileHeight)));
          }
          else {
            if (startY + screenHeight > mapHeight / tileHeight) {
              mapLayers[i].setOffset(null, Math.floor(mapHeight / tileHeight) - (screenHeight * tileHeight) / 2) ;
            }
            else {
              mapLayers[i].setOffset(null, Math.floor(-tileHeight * posY + (screenHeight / 2 * tileHeight)));
            }
          }
        }
      }
      if (screenWidth * tileWidth > mapWidth) {
        for (i = 0; i < mapLayers.length; i++) {
          mapLayers[i].setOffset(Math.floor(screenWidth * tileWidth / 2 - mapWidth / 2), Math.floor(screenHeight * tileHeight / 2 - mapHeight / 2));
        }
      }
      else {
        for (i = 0; i < mapLayers.length; i++) {
          if (startX < 0) {
            mapLayers[i].setOffset(Math.floor(-tileWidth * posX + (posX * tileWidth)), null);
          }
          else {
            if (startX + screenWidth > mapWidth / tileWidth) {
              mapLayers[i].setOffset(-(Math.floor(mapWidth / tileWidth)  - screenWidth) * tileWidth, null);
            }
            else {
              mapLayers[i].setOffset(Math.floor(-tileWidth * posX + (screenWidth / 2 * tileHeight)), null);
            }
          }
        }
      }
      xyMapOffset = mapLayers[0].getOffset();
      focusX = posX * tileWidth + xyMapOffset.x;
      focusY = posY * tileHeight + xyMapOffset.y;
      var xyNextPos = _getXYCoords(focusX - xyMapOffset.x, focusY - xyMapOffset.y);
      return {
        startX: Math.floor(xyNextPos.x - rangeX / 2),
        startY: Math.floor(xyNextPos.y - rangeY / 2),
        pinFocusX: Math.floor(focusX),
        pinFocusY: Math.floor(focusY),
        tileX: Math.floor(posX),
        tileY: Math.floor(posY)
      };
    }

    // direction: "up", "down", "left", "right" - distance: int
    function _move(direction, distance, startX, startY, rangeX, rangeY) {
      var xyMapOffset = mapLayers[0].getOffset();
      var xyNextPos = _getXYCoords(focusX - xyMapOffset.x, focusY - xyMapOffset.y);
      switch(direction) {
        case "up":
          if (xyNextPos.y - 1 <= startY + screenHeight / 2 && focusY < (screenHeight / 2 * tileHeight) && xyMapOffset.y <= 0) {
            for (i = 0; i < mapLayers.length; i++) {
              mapLayers[i].move("up", distance);
            }
          }
          else {
            focusY -= distance;
          }
        break;
        case "down":
          if (xyNextPos.y >= screenHeight / 2 && focusY > (screenHeight / 2 * tileHeight) && xyMapOffset.y >= -mapHeight + tileHeight + focusY + (screenHeight / 2 * tileHeight)) {
            for (i = 0; i < mapLayers.length; i++) {
              mapLayers[i].move("down", distance);
            }
          }
          else {
            focusY += distance;
          }
        break;
        case "left":
          if (xyNextPos.x - 1 <= startX + screenWidth / 2 && focusX < (screenWidth / 2 * tileWidth) && xyMapOffset.x <= 0) {
            for (i = 0; i < mapLayers.length; i++) {
              mapLayers[i].move("left", distance);
            }
          }
          else {
            focusX -= distance;
          }
        break;
        case "right":
          if (xyNextPos.x >= screenWidth / 2 && xyMapOffset.x >= -mapWidth + focusX + (screenWidth / 2 * tileWidth)) {
            for (i = 0; i < mapLayers.length; i++) {
              mapLayers[i].move("right", distance);
            }
          }
          else {
            focusX += distance;
          }
        break;
      }
      startX = xyNextPos.x - rangeX / 2;
      startY = xyNextPos.y - rangeY / 2;

      return {
        startX: Math.floor(startX),
        startY: Math.floor(startY),
        pinFocusX: Math.floor(focusX),
        pinFocusY: Math.floor(focusY),
        tileX: Math.floor(xyNextPos.x),
        tileY: Math.floor(xyNextPos.y)
      };
      // Returns where to start drawing the tiles from.
      // pinFocus represents a precise location withn the map.
    }

    return {
      setup: function(mapLayers, mapWidth, mapHeight, tileWidth, tileHeight, screenWidth, screenHeight, curZoom) {
        return _setup(mapLayers, mapWidth, mapHeight, tileWidth, tileHeight, screenWidth, screenHeight, curZoom);
      },

      setFocus: function(posX, posY, rangeX, rangeY) {
        return _setFocus(posX, posY, rangeX, rangeY);
      },

      getFocus: function() {
        return {
          startX: startX,
          startY: startY,
          pinFocusX: focusX,
          pinFocusY: focusY
        };
      },

      move: function(direction, distance, startX, startY, rangeX, rangeY) {
        return _move(direction, distance, startX, startY, rangeX, rangeY);
      }

    };
  };
});<commit_msg>Dropped unnecesary var passing for panning and added ability to alter pin focus<commit_after>/*  Copyright (c) 2014 Iain Hamilton

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE. */

define([], function() {
  return function () {

    var mapLayers;

    var mapWidth;
    var mapHeight;
    var tileWidth;
    var tileHeight;
    var screenWidth;
    var screenHeight;

    var mapOffsetX;
    var mapOffsetY;

    var curZoom;
    var startX = 0;
    var startY = 0;
    var focusX = 0;
    var focusY = 0;
    var rangeX = 0;
    var rangeY = 0;

    var isometric = false;

    var xyNextPos = {};

    function _setup(layers, mapW, mapH, tileW, tileH, screenW, screenH, curZ) {
      mapLayers = layers;
      mapWidth = mapW;
      mapHeight = mapH;
      tileWidth = tileW;
      tileHeight = tileH;
      curZoom = curZ || 1;
      screenWidth = screenW;
      screenHeight = screenH;
      return {
        startX: startX,
        startY: startY,
        pinFocusX: focusX,
        pinFocusY: focusY
      };
    }

    function _getXYCoords(x, y) {
      var positionY, positionX;
      if (!isometric) {
        positionY = Math.round((y - (tileHeight * curZoom) / 2)/ (tileHeight * curZoom));
        positionX = Math.round((x - (tileWidth * curZoom) / 2)/ (tileWidth * curZoom));
      }
      else {
        positionY = (2 * (y - mapOffsetY) - x + mapOffsetX) / 2;
        positionX = x + positionY - mapOffsetX - (tileHeight * curZoom);
        positionY = Math.round(positionY / (tileHeight * curZoom));
        positionX = Math.round(positionX / (tileHeight * curZoom));
      }
      return {x: positionX, y: positionY};
    }

    function _setFocus(posX, posY, cameraRangeX, cameraRangeY) {
      var xyMapOffset;
      var i;
      rangeX = cameraRangeX;
      rangeY = cameraRangeY;

      startX = posX - screenWidth / 2;
      startY = posY - screenHeight / 2;

      if (screenHeight * tileHeight > mapHeight) {
        for (i = 0; i < mapLayers.length; i++) {
          mapLayers[i].setOffset(null, Math.floor(screenHeight * tileHeight / 2 - mapHeight / 2));
        }
      }
      else {
        for (i = 0; i < mapLayers.length; i++) {
          if (startY < 0) {
            mapLayers[i].setOffset(null, Math.floor(-tileHeight * posY + (posY * tileHeight)));
          }
          else {
            if (startY + screenHeight > mapHeight / tileHeight) {
              mapLayers[i].setOffset(null, Math.floor(mapHeight / tileHeight) - (screenHeight * tileHeight) / 2) ;
            }
            else {
              mapLayers[i].setOffset(null, Math.floor(-tileHeight * posY + (screenHeight / 2 * tileHeight)));
            }
          }
        }
      }
      if (screenWidth * tileWidth > mapWidth) {
        for (i = 0; i < mapLayers.length; i++) {
          mapLayers[i].setOffset(Math.floor(screenWidth * tileWidth / 2 - mapWidth / 2), Math.floor(screenHeight * tileHeight / 2 - mapHeight / 2));
        }
      }
      else {
        for (i = 0; i < mapLayers.length; i++) {
          if (startX < 0) {
            mapLayers[i].setOffset(Math.floor(-tileWidth * posX + (posX * tileWidth)), null);
          }
          else {
            if (startX + screenWidth > mapWidth / tileWidth) {
              mapLayers[i].setOffset(-(Math.floor(mapWidth / tileWidth)  - screenWidth) * tileWidth, null);
            }
            else {
              mapLayers[i].setOffset(Math.floor(-tileWidth * posX + (screenWidth / 2 * tileHeight)), null);
            }
          }
        }
      }
      xyMapOffset = mapLayers[0].getOffset();
      focusX = posX * tileWidth + xyMapOffset.x;
      focusY = posY * tileHeight + xyMapOffset.y;
      xyNextPos = _getXYCoords(focusX - xyMapOffset.x, focusY - xyMapOffset.y);
      return {
        startX: Math.floor(xyNextPos.x - rangeX / 2),
        startY: Math.floor(xyNextPos.y - rangeY / 2),
        pinFocusX: Math.floor(focusX),
        pinFocusY: Math.floor(focusY),
        tileX: Math.floor(posX),
        tileY: Math.floor(posY)
      };
    }

    // direction: "up", "down", "left", "right" - distance: int
    function _move(direction, distance) {
      var xyMapOffset = mapLayers[0].getOffset();
      xyNextPos = _getXYCoords(focusX - xyMapOffset.x, focusY - xyMapOffset.y);
      switch(direction) {
        case "up":
          if (xyNextPos.y - 1 <= startY + screenHeight / 2 && focusY < (screenHeight / 2 * tileHeight) && xyMapOffset.y <= 0) {
            for (i = 0; i < mapLayers.length; i++) {
              mapLayers[i].move("up", distance);
            }
          }
          else {
            focusY -= distance;
          }
        break;
        case "down":
          if (xyNextPos.y >= screenHeight / 2 && focusY > (screenHeight / 2 * tileHeight) && xyMapOffset.y >= -mapHeight + tileHeight + focusY + (screenHeight / 2 * tileHeight)) {
            for (i = 0; i < mapLayers.length; i++) {
              mapLayers[i].move("down", distance);
            }
          }
          else {
            focusY += distance;
          }
        break;
        case "left":
          if (xyNextPos.x - 1 <= startX + screenWidth / 2 && focusX < (screenWidth / 2 * tileWidth) && xyMapOffset.x <= 0) {
            for (i = 0; i < mapLayers.length; i++) {
              mapLayers[i].move("left", distance);
            }
          }
          else {
            focusX -= distance;
          }
        break;
        case "right":
          if (xyNextPos.x >= screenWidth / 2 && xyMapOffset.x >= -mapWidth + focusX + (screenWidth / 2 * tileWidth)) {
            for (i = 0; i < mapLayers.length; i++) {
              mapLayers[i].move("right", distance);
            }
          }
          else {
            focusX += distance;
          }
        break;
      }
      startX = xyNextPos.x - rangeX / 2;
      startY = xyNextPos.y - rangeY / 2;

      return {
        startX: Math.floor(startX),
        startY: Math.floor(startY),
        pinFocusX: Math.floor(focusX),
        pinFocusY: Math.floor(focusY),
        tileX: Math.floor(xyNextPos.x),
        tileY: Math.floor(xyNextPos.y)
      };
      // Returns where to start drawing the tiles from.
      // pinFocus represents a precise location withn the map.
    }

    return {
      setup: function(mapLayers, mapWidth, mapHeight, tileWidth, tileHeight, screenWidth, screenHeight, curZoom) {
        return _setup(mapLayers, mapWidth, mapHeight, tileWidth, tileHeight, screenWidth, screenHeight, curZoom);
      },

      setFocus: function(posX, posY, rangeX, rangeY) {
        return _setFocus(posX, posY, rangeX, rangeY);
      },

      setPinFocusY: function(y) {
        focusY = y;
        return {
          startX: Math.floor(startX),
          startY: Math.floor(startY),
          pinFocusX: focusX,
          pinFocusY: focusY,
          tileX: Math.floor(xyNextPos.x),
          tileY: Math.floor(xyNextPos.y)
        };
      },

      setPinFocusX: function(x) {
        focusX = x;
        return {
          startX: Math.floor(startX),
          startY: Math.floor(startY),
          pinFocusX: focusX,
          pinFocusY: focusY,
          tileX: Math.floor(xyNextPos.x),
          tileY: Math.floor(xyNextPos.y)
        };
      },

      getFocus: function() {
        return {
          startX: Math.floor(startX),
          startY: Math.floor(startY),
          pinFocusX: focusX,
          pinFocusY: focusY,
          tileX: Math.floor(xyNextPos.x),
          tileY: Math.floor(xyNextPos.y)
        };
      },

      move: function(direction, distance) {
        return _move(direction, distance);
      }

    };
  };
});<|endoftext|>


<commit_before>// vim: set ts=2 sw=2 et colorcolumn=100 :

/**
 * Namespace
 * @namespace
 */
var geochart_geojson = {};

(function(context) {

/**
 * Create a GeoChart with GeoJSON support
 * @class
 *
 * These charts are very similar to the Google Charts geochart, but with GeoJSON support.
 *
 * Code based on many Google Charts and Google Maps API guides and references.
 *
 * See:
 *
 * - https://developers.google.com/chart/interactive/docs/dev/
 * - https://developers.google.com/chart/interactive/docs/gallery/geochart
 * - https://developers.google.com/chart/interactive/docs/datatables_dataviews
 * - https://developers.google.com/chart/interactive/docs/reference
 * - https://developers.google.com/maps/documentation/javascript/
 *
 * @param {object} container - The HTML container for the chart.
 */
context.GeoChart = function(container) {
  this.container = container;

  this.data_ = null;
  this.options_ = null;
  // The inner Google Maps map object
  // This object will hold the GeoJSON map (in its overlay layer), the tooltip overlay and the
  // legend control.
  // Optionally, it will also handle the underlying map layer (map, satellite or simple map) and
  // the map control (zoom, map drag). These features are disabled by default, so the
  this.maps_map_ = null;
  this.tooltip_ = null;
  this.legend_ = null;
  // Min and max values of the DataTable rows
  // Used in the gradient color generation.
  this.min_ = 0;
  this.max_ = 0;
  // Feature selected by the user
  this.feature_selected_ = null;
}

context.GeoChart.prototype.CONSTANTS = {
  // zIndex of selected or highlighted features
  // The selected (click) and highlighted (hover) features must have a zIndex higher than
  // the other features.
  selectedZIndex: 999,
  highlightedZIndex: 1000
}

context.GeoChart.prototype.DEFAULT_OPTIONS = {
  mapsBackground: "none",
  mapsControl: false,
  featuresStyle: {
    fillColor: "#f5f5f5",
    strokeColor: '#dddddd',
    fillOpacity: 1,
    strokeWeight: 1,
    cursor: "default"
  },
  featuresHighlightedStyle: {
    strokeWeight: 3,
    strokeOpacity: 1,
  },
  featuresGradientColors: ["#efe6dc", "#109618"],
  featuresGradientStrokeColors: ["#d7cfc6", "0e8716"]
}

// TODO Implement other `mapsBackground` and `mapsControl` options
context.GeoChart.prototype.getMapsOptions_ = function() {
  var maps_options = this.options_.mapsOptions;

  if (this.options_.mapsBackground === "none") {
    maps_options["styles"] = [{
      "stylers": [{"visibility": "off"}]
    }];
    maps_options["backgroundColor"] = "none";
  } else {
    throw "Invalid `mapsBackground` option";
  }

  if (this.options_.mapsControl === false) {
    maps_options["disableDefaultUI"] = true;
    maps_options["scrollwheel"] = false;
    maps_options["draggable"] = false;
    maps_options["disableDoubleClickZoom"] = true;
  } else {
    throw "Invalid `mapsControl` option";
  }

  return maps_options;
}

context.GeoChart.prototype.draw = function(data, options) {
  this.data_ = data;
  // XXX This doesn't run a deep copy. So, if someday `DEFAULT_OPTIONS` has objects in its values,
  // the line above won't work anymore.
  // See: https://stackoverflow.com/questions/27936772/how-to-deep-merge-instead-of-shallow-merge
  var merged_options = Object.assign({}, context.GeoChart.prototype.DEFAULT_OPTIONS, options);
  this.options_ = merged_options;

  var this_ = this;

  // Create the Google Maps object
  var maps_options = this.getMapsOptions_();
  // TODO We could implement custom zooming when mapsBackground = 'none' using custom
  // projections.
  // See: https://groups.google.com/forum/#!topic/google-maps-js-api-v3/AbOHZlLQLCg
  this.map_ = new google.maps.Map(this.container, maps_options);

  // Load the GeoJSON data
  this.map_.data.loadGeoJson(
      this.options_.geoJson, this.options_.geoJsonOptions,
      function(features) {
        var min = Number.MAX_VALUE;
        var max = -Number.MAX_VALUE;

        // Populate the feature "data-" properties
        for (var row = 0; row < data.getNumberOfRows(); row++) {
          var id = data.getValue(row, 0);
          var value = data.getValue(row, 1);
          var feature = this_.map_.data.getFeatureById(id);

          // Keep track of min and max values
          if (value < min) {
            min = value;
          }
          if (value > max) {
            max = value;
          }
          feature.setProperty("data-row", row);
          feature.setProperty("data-value", value);
        }
        this_.min_ = min;
        this_.max_ = max;

        // Trigger the ready event
        // See: https://developers.google.com/chart/interactive/docs/dev/events#the-ready-event
        google.visualization.events.trigger(this_, 'ready', null);
      }
  );

  // Define the feature styles
  this.map_.data.setStyle(function(feature) {
    // Default style
    var style = Object.assign({}, this_.DEFAULT_OPTIONS.featuresStyle);

    // Feature with data style
    // Colorize the features with data (using the gradient colors)
    if (feature.getProperty("data-value") !== undefined) {
      var fill_color_arr = [];
      var stroke_color_arr = [];

      var gradient_colors_arr = [
          this_.getColorArray_(this_.DEFAULT_OPTIONS.featuresGradientColors[0]),
          this_.getColorArray_(this_.DEFAULT_OPTIONS.featuresGradientColors[1])
      ];
      var gradient_stroke_colors_arr = [
          this_.getColorArray_(this_.DEFAULT_OPTIONS.featuresGradientStrokeColors[0]),
          this_.getColorArray_(this_.DEFAULT_OPTIONS.featuresGradientStrokeColors[1])
      ];
      var relative_value = this_.getRelativeValue_(feature.getProperty("data-value"));

      for (var i = 0; i < 3; i++) {
        fill_color_arr[i] =
            (gradient_colors_arr[1][i] - gradient_colors_arr[0][i]) * relative_value +
            gradient_colors_arr[0][i];
        stroke_color_arr[i] =
            ((gradient_stroke_colors_arr[1][i] - gradient_stroke_colors_arr[0][i]) *
            relative_value) + gradient_stroke_colors_arr[0][i];
      }

      style = Object.assign(style, {
        fillColor: 'rgb(' + fill_color_arr[0] + ',' + fill_color_arr[1] + ',' +
            fill_color_arr[2] + ')',
        strokeColor: 'rgb(' + stroke_color_arr[0] + ',' + stroke_color_arr[1] + ',' +
            stroke_color_arr[2] + ')'
      });

      // Selected feature style
      if (feature.getProperty("data-selected") === true) {
        style = Object.assign(
            style, this_.DEFAULT_OPTIONS.featuresHighlightedStyle,
            {zIndex: this_.CONSTANTS.selectedZIndex}
        );
      }
    }

    return style;
  });

}

// Based on: https://stackoverflow.com/questions/5623838/rgb-to-hex-and-hex-to-rgb
context.GeoChart.prototype.getColorArray_ = function(color) {
  var short_regex = /^#?([\da-f])([\da-f])([\da-f])$/i;
  var regex = /^#?([\da-f]{2})([\da-f]{2})([\da-f]{2})$/i;

  var color_array = null;

  color = color.replace(short_regex, function(m, r, g, b) {
    return "#" + r + r + g + g + b + b;
  });
  var result = regex.exec(color);
  if (! result) {
    throw "Invalid color string";
  }
  color_array = [parseInt(result[1], 16), parseInt(result[2], 16), parseInt(result[3], 16)];

  return color_array;
}

context.GeoChart.prototype.getRelativeValue_ = function(value) {
  return (value - this.min_) / (this.max_ - this.min_);
}

// Entry selected by the user
// See: https://developers.google.com/chart/interactive/docs/reference#getselection
context.GeoChart.prototype.getSelection = function() {
  if (! this.feature_selected_) {
    return [];
  } else {
    return [{row: this.feature_selected_.getProperty("data-row"), column: null}];
  }
}

context.GeoChart.prototype.setSelection = function(selection) {
  // Implemented only for a single row selection
  if (Array.isArray(selection) && selection.length === 1) {
      var id = this.data_.getValue(selection[0].row, 0);
      this.feature_selected_ = this.map_.data.getFeatureById(id);
      this.feature_selected_.setProperty("data-selected", true);
  }
}

})(geochart_geojson);
<commit_msg>Adding basic highlight effects<commit_after>// vim: set ts=2 sw=2 et colorcolumn=100 :

/**
 * Namespace
 * @namespace
 */
var geochart_geojson = {};

(function(context) {

/**
 * Create a GeoChart with GeoJSON support
 * @class
 *
 * These charts are very similar to the Google Charts geochart, but with GeoJSON support.
 *
 * Code based on many Google Charts and Google Maps API guides and references.
 *
 * See:
 *
 * - https://developers.google.com/chart/interactive/docs/dev/
 * - https://developers.google.com/chart/interactive/docs/gallery/geochart
 * - https://developers.google.com/chart/interactive/docs/datatables_dataviews
 * - https://developers.google.com/chart/interactive/docs/reference
 * - https://developers.google.com/maps/documentation/javascript/
 *
 * @param {object} container - The HTML container for the chart.
 */
context.GeoChart = function(container) {
  this.container = container;

  this.data_ = null;
  this.options_ = null;
  // The inner Google Maps map object
  // This object will hold the GeoJSON map (in its overlay layer), the tooltip overlay and the
  // legend control.
  // Optionally, it will also handle the underlying map layer (map, satellite or simple map) and
  // the map control (zoom, map drag). These features are disabled by default, so the
  this.maps_map_ = null;
  this.tooltip_ = null;
  this.legend_ = null;
  // Min and max values of the DataTable rows
  // Used in the gradient color generation.
  this.min_ = 0;
  this.max_ = 0;
  // Feature selected by the user
  this.feature_selected_ = null;
}

context.GeoChart.prototype.CONSTANTS = {
  // zIndex of selected or highlighted features
  // The selected (click) and highlighted (hover) features must have a zIndex higher than
  // the other features.
  selectedZIndex: 999,
  highlightedZIndex: 1000
}

context.GeoChart.prototype.DEFAULT_OPTIONS = {
  mapsBackground: "none",
  mapsControl: false,
  featuresStyle: {
    fillColor: "#f5f5f5",
    strokeColor: '#dddddd',
    fillOpacity: 1,
    strokeWeight: 1,
    cursor: "default"
  },
  featuresHighlightedStyle: {
    strokeWeight: 3,
    strokeOpacity: 1,
  },
  featuresGradientColors: ["#efe6dc", "#109618"],
  featuresGradientStrokeColors: ["#d7cfc6", "0e8716"]
}

// TODO Implement other `mapsBackground` and `mapsControl` options
context.GeoChart.prototype.getMapsOptions_ = function() {
  var maps_options = this.options_.mapsOptions;

  if (this.options_.mapsBackground === "none") {
    maps_options["styles"] = [{
      "stylers": [{"visibility": "off"}]
    }];
    maps_options["backgroundColor"] = "none";
  } else {
    throw "Invalid `mapsBackground` option";
  }

  if (this.options_.mapsControl === false) {
    maps_options["disableDefaultUI"] = true;
    maps_options["scrollwheel"] = false;
    maps_options["draggable"] = false;
    maps_options["disableDoubleClickZoom"] = true;
  } else {
    throw "Invalid `mapsControl` option";
  }

  return maps_options;
}

context.GeoChart.prototype.draw = function(data, options) {
  this.data_ = data;
  // XXX This doesn't run a deep copy. So, if someday `DEFAULT_OPTIONS` has objects in its values,
  // the line above won't work anymore.
  // See: https://stackoverflow.com/questions/27936772/how-to-deep-merge-instead-of-shallow-merge
  var merged_options = Object.assign({}, context.GeoChart.prototype.DEFAULT_OPTIONS, options);
  this.options_ = merged_options;

  var this_ = this;

  // Create the Google Maps object
  var maps_options = this.getMapsOptions_();
  // TODO We could implement custom zooming when mapsBackground = 'none' using custom
  // projections.
  // See: https://groups.google.com/forum/#!topic/google-maps-js-api-v3/AbOHZlLQLCg
  this.map_ = new google.maps.Map(this.container, maps_options);

  // Load the GeoJSON data
  this.map_.data.loadGeoJson(
      this.options_.geoJson, this.options_.geoJsonOptions,
      function(features) {
        var min = Number.MAX_VALUE;
        var max = -Number.MAX_VALUE;

        // Populate the feature "data-" properties
        for (var row = 0; row < data.getNumberOfRows(); row++) {
          var id = data.getValue(row, 0);
          var value = data.getValue(row, 1);
          var feature = this_.map_.data.getFeatureById(id);

          // Keep track of min and max values
          if (value < min) {
            min = value;
          }
          if (value > max) {
            max = value;
          }
          feature.setProperty("data-row", row);
          feature.setProperty("data-value", value);
        }
        this_.min_ = min;
        this_.max_ = max;

        // Trigger the ready event
        // See: https://developers.google.com/chart/interactive/docs/dev/events#the-ready-event
        google.visualization.events.trigger(this_, 'ready', null);
      }
  );

  // Define the feature styles
  this.map_.data.setStyle(function(feature) {
    // Default style
    var style = Object.assign({}, this_.DEFAULT_OPTIONS.featuresStyle);

    // Feature with data style
    // Colorize the features with data (using the gradient colors)
    if (feature.getProperty("data-value") !== undefined) {
      var fill_color_arr = [];
      var stroke_color_arr = [];

      var gradient_colors_arr = [
          this_.getColorArray_(this_.DEFAULT_OPTIONS.featuresGradientColors[0]),
          this_.getColorArray_(this_.DEFAULT_OPTIONS.featuresGradientColors[1])
      ];
      var gradient_stroke_colors_arr = [
          this_.getColorArray_(this_.DEFAULT_OPTIONS.featuresGradientStrokeColors[0]),
          this_.getColorArray_(this_.DEFAULT_OPTIONS.featuresGradientStrokeColors[1])
      ];
      var relative_value = this_.getRelativeValue_(feature.getProperty("data-value"));

      for (var i = 0; i < 3; i++) {
        fill_color_arr[i] =
            (gradient_colors_arr[1][i] - gradient_colors_arr[0][i]) * relative_value +
            gradient_colors_arr[0][i];
        stroke_color_arr[i] =
            ((gradient_stroke_colors_arr[1][i] - gradient_stroke_colors_arr[0][i]) *
            relative_value) + gradient_stroke_colors_arr[0][i];
      }

      style = Object.assign(style, {
        fillColor: 'rgb(' + fill_color_arr[0] + ',' + fill_color_arr[1] + ',' +
            fill_color_arr[2] + ')',
        strokeColor: 'rgb(' + stroke_color_arr[0] + ',' + stroke_color_arr[1] + ',' +
            stroke_color_arr[2] + ')'
      });

      // Selected feature style
      if (feature.getProperty("data-selected") === true) {
        style = Object.assign(
            style, this_.DEFAULT_OPTIONS.featuresHighlightedStyle,
            {zIndex: this_.CONSTANTS.selectedZIndex}
        );
      }
    }

    return style;
  });

  this.map_.data.addListener('mouseover', function(event) {
    var highlight_style = Object.assign(
        {}, this_.DEFAULT_OPTIONS.featuresHighlightedStyle,
        {zIndex: this_.CONSTANTS.highlightedZIndex});

    if (event.feature !== this_.feature_selected_) {
        this_.map_.data.revertStyle();
        this_.map_.data.overrideStyle(event.feature, highlight_style);
    }
  });

  this.map_.data.addListener('mouseout', function(event) {
    if (event.feature !== this_.feature_selected_) {
        this_.map_.data.revertStyle();
    }
  });

}

// Based on: https://stackoverflow.com/questions/5623838/rgb-to-hex-and-hex-to-rgb
context.GeoChart.prototype.getColorArray_ = function(color) {
  var short_regex = /^#?([\da-f])([\da-f])([\da-f])$/i;
  var regex = /^#?([\da-f]{2})([\da-f]{2})([\da-f]{2})$/i;

  var color_array = null;

  color = color.replace(short_regex, function(m, r, g, b) {
    return "#" + r + r + g + g + b + b;
  });
  var result = regex.exec(color);
  if (! result) {
    throw "Invalid color string";
  }
  color_array = [parseInt(result[1], 16), parseInt(result[2], 16), parseInt(result[3], 16)];

  return color_array;
}

context.GeoChart.prototype.getRelativeValue_ = function(value) {
  return (value - this.min_) / (this.max_ - this.min_);
}

// Entry selected by the user
// See: https://developers.google.com/chart/interactive/docs/reference#getselection
context.GeoChart.prototype.getSelection = function() {
  if (! this.feature_selected_) {
    return [];
  } else {
    return [{row: this.feature_selected_.getProperty("data-row"), column: null}];
  }
}

context.GeoChart.prototype.setSelection = function(selection) {
  var id = "";
  var feature = null;

  // Implemented only for a single row selection
  if (Array.isArray(selection) && selection.length === 1) {
      id = this.data_.getValue(selection[0].row, 0);
      feature = this.map_.data.getFeatureById(id);
      this.selectFeature_(feature);
  }
}

context.GeoChart.prototype.selectFeature_ = function(feature) {
  this.feature_selected_ = feature;
  this.feature_selected_.setProperty("data-selected", true);
}

})(geochart_geojson);
<|endoftext|>


<commit_before>module.exports = function(app, Users) {

    app.get('/settings', app.auth.isAuthenticated, function(req, res) {
        return res.render('user_settings', { user: req.user });

    });

    app.post('/settings', app.auth.isAuthenticated, function(req, res) {
        req.user.email_address = req.body.email;
        req.user.alert_when_friends_join = req.body.alert_when_friends_join;
        req.user.alert_when_follow = req.body.alert_when_follow;

    var new_username = req.body.username;

    if (!new_username) {
    return res.json({errors: ['Username cannot be empty.']});
    }

    if (req.user.old_username) {
    return res.json({errors: ['Username cannot be changed more than once.']});
    }

    if (new_username === req.user.username) {
    return res.json({errors: ['New Username cannot be same as existing username.']});
    }

    // make sure new username is available
    Users.findOne({ $or: [ { username : new_username }, { old_username : new_username } ]}, function(err, existingUser) {

        if (err) {
            return res.json({errors: ['Something went wrong.']});
        }

        if (existingUser) {
            // send error
            return res.json({errors: ['Username has been taken.']});
        } else {
            req.user.old_username = req.user.username;
            req.user.username = req.body.username;
            req.user.save();
            return res.json({passed: true});
        }
    });

    });

}<commit_msg>Update setting router sycn with master<commit_after>module.exports = function(app, Users) {

    app.get('/settings', app.auth.isAuthenticated, function(req, res) {
        return res.render('user_settings', { user: req.user });

    });

    app.post('/settings', app.auth.isAuthenticated, function(req, res) {

        var params = req.body;
        req.user.email_address = params.user.email_address;
        req.user.alert_when_friends_join = params.user.alert_when_friends_join;
        req.user.alert_when_follow = params.user.alert_when_follow;

    if (params.changeUsername) {
    var new_username = params.user.username;

    if (!new_username) {
      return res.json({errors: ['Username cannot be empty.']});
    }

    if (req.user.old_username) {
      return res.json({errors: ['Username cannot be changed more than once.']});
    }

    if (new_username === req.user.username) {
      return res.json({errors: ['New Username cannot be same as existing username.']});
    }n res.json({errors: ['New Username cannot be same as existing username.']});
    }

    // make sure new username is available
    Users.findOne({ $or: [ { username : new_username }, { old_username : new_username } ]}, function(err, existingUser) {

        if (err) {
            return res.json({errors: ['Something went wrong.']});
        }

        if (existingUser) {
            // send error
            return res.json({errors: ['Username has been taken.']});
        } else {
            req.user.old_username = req.user.username;
            req.user.username = req.body.username;
            req.user.save();
            return res.json({passed: true});
        }
    });

    });

}<|endoftext|>


<commit_before>(function() {
    'use strict';

    Game.GUI.PauseScreen = function(game, parent) {
        Phaser.Group.call(this, game, parent, 'PauseScreen');

        /**
         * The padding in pixels between buttons
         * @type {Number}
         */
        this.padding = 20;

        var bmd = this.game.make.bitmapData(this.game.width, this.game.height);
        bmd.fill(0, 0, 0, 0.75);
        /**
         * The pause screen background
         * @type {Phaser}
         */
        this.bg = new Phaser.Image(this.game, 0, 0, bmd);
        this.bg.bmd = bmd;
        this.add(this.bg);

        /**
         * The resume button
         * @type {Game.GUI.Button}
         */
        this.resumeBtn = new Game.GUI.Button(this.game, this.game.width * 0.5, this.game.height * 0.4, 'knapp', 'Resume', 'font', this.resume, this);
        this.resumeBtn.scale.setTo(0.8);
        this.add(this.resumeBtn);

        /**
         * The toggle mute button
         * @type {Game.GUI.Button}
         */
        this.musicBtn = new Game.GUI.Button(this.game, this.game.width * 0.5, this.resumeBtn.position.y + this.resumeBtn.height + this.padding, 'knapp', 'music_btn', 'font', this.toggleMusic, this);
        this.musicBtn.scale.setTo(0.8);
        this.musicBtn.position.x -= (this.musicBtn.width + this.padding) * 0.5;
        this._refreshMusicBtn();
        this.add(this.musicBtn);

        /**
         * The toggle fullscreen button
         * @type {Game.GUI.Button}
         */
        this.fullscreen = new Game.GUI.Button(this.game, this.game.width * 0.5, this.resumeBtn.position.y + this.resumeBtn.height + this.padding, 'knapp', 'Toggle\nFullscreen', 'font', this.toggleFullscreen, this);
        this.fullscreen.scale.setTo(0.8);
        this.fullscreen.position.x += (this.musicBtn.width + this.padding) * 0.5;
        this.add(this.fullscreen);

        this.multiplayerBtn = new Game.GUI.Button(this.game, this.game.width * 0.5, this.musicBtn.position.y + this.musicBtn.height + this.padding, 'knapp', 'Multiplayer:\noff', 'font', this.toggleMultiplayer, this);
        this.multiplayerBtn.scale.setTo(0.8);
        this.multiplayerBtn.position.x -= (this.multiplayerBtn.width + this.padding) * 0.5;
        this.add(this.multiplayerBtn);

        this.alpha = 0;
        this.game.add.tween(this).to({alpha: 1}, 300).start();
    };

    Game.GUI.PauseScreen.prototype = Object.create(Phaser.Group.prototype);
    Game.GUI.PauseScreen.prototype.constructor = Game.GUI.PauseScreen;

    Game.GUI.PauseScreen.prototype.resume = function() {
        this.game.add.tween(this).to({alpha: 0}, 300).start().onComplete.add(function() {
            this.game.state.getCurrentState().resume();
        }, this);
    };

    Game.GUI.PauseScreen.prototype.pause = function() {
        this.game.state.getCurrentState().resume();
    };

    Game.GUI.PauseScreen.prototype.toggleMusic = function() {
        this.game.state.getCurrentState().toggleMusic();
        this._refreshMusicBtn();
    };

    Game.GUI.PauseScreen.prototype._refreshMusicBtn = function() {
        this.musicBtn.text = !this.game.musicMuted ? 'Music: on' : 'Music: off';
    };

    Game.GUI.PauseScreen.prototype.toggleFullscreen = function() {
        this.game.state.getCurrentState().toggleFullScreen();
    };

    Game.GUI.PauseScreen.prototype.toggleMultiplayer = function() {
        if (this.game.mpClient) {
            this.game.mpClient.disconnect();
            this.game.mpClient = null;
            this.multiplayerBtn.text = 'Multiplayer:\noff';
        } else {
            if (io) {
                var serverUrl = 'http://{0}:{1}'.format(window.location.hostname, 3001);
                this._createMPClient(serverUrl);
                this.multiplayerBtn.text = 'Multiplayer:\non';
            }
        }
    };

    Game.GUI.PauseScreen.prototype._createMPClient = function(url) {
        this.game.mpClient = new Game.MPClient(this.game, url);
    };

})();
<commit_msg>Changed position on toggle music and multiplayer buttons<commit_after>(function() {
    'use strict';

    Game.GUI.PauseScreen = function(game, parent) {
        Phaser.Group.call(this, game, parent, 'PauseScreen');

        /**
         * The padding in pixels between buttons
         * @type {Number}
         */
        this.padding = 20;

        var bmd = this.game.make.bitmapData(this.game.width, this.game.height);
        bmd.fill(0, 0, 0, 0.75);
        /**
         * The pause screen background
         * @type {Phaser}
         */
        this.bg = new Phaser.Image(this.game, 0, 0, bmd);
        this.bg.bmd = bmd;
        this.add(this.bg);

        /**
         * The resume button
         * @type {Game.GUI.Button}
         */
        this.resumeBtn = new Game.GUI.Button(this.game, this.game.width * 0.5, this.game.height * 0.4, 'knapp', 'Resume', 'font', this.resume, this);
        this.resumeBtn.scale.setTo(0.8);
        this.add(this.resumeBtn);

        /**
         * The toggle multiplayer button
         * @type {Game.GUI.Button}
         */
        this.multiplayerBtn = new Game.GUI.Button(this.game, this.game.width * 0.5, this.resumeBtn.position.y + this.resumeBtn.height + this.padding, 'knapp', 'Multiplayer:\noff', 'font', this.toggleMultiplayer, this);
        this.multiplayerBtn.scale.setTo(0.8);
        this.multiplayerBtn.position.x -= (this.multiplayerBtn.width + this.padding) * 0.5;
        this.add(this.multiplayerBtn);

        /**
         * The toggle mute button
         * @type {Game.GUI.Button}
         */
        this.musicBtn = new Game.GUI.Button(this.game, this.game.width * 0.5, this.multiplayerBtn.position.y + this.multiplayerBtn.height + this.padding, 'knapp', 'music_btn', 'font', this.toggleMusic, this);
        this.musicBtn.scale.setTo(0.8);
        this.musicBtn.position.x -= (this.musicBtn.width + this.padding) * 0.5;
        this._refreshMusicBtn();
        this.add(this.musicBtn);

        /**
         * The toggle fullscreen button
         * @type {Game.GUI.Button}
         */
        this.fullscreen = new Game.GUI.Button(this.game, this.game.width * 0.5, this.resumeBtn.position.y + this.resumeBtn.height + this.padding, 'knapp', 'Toggle\nFullscreen', 'font', this.toggleFullscreen, this);
        this.fullscreen.scale.setTo(0.8);
        this.fullscreen.position.x += (this.musicBtn.width + this.padding) * 0.5;
        this.add(this.fullscreen);

        this.alpha = 0;
        this.game.add.tween(this).to({alpha: 1}, 300).start();
    };

    Game.GUI.PauseScreen.prototype = Object.create(Phaser.Group.prototype);
    Game.GUI.PauseScreen.prototype.constructor = Game.GUI.PauseScreen;

    Game.GUI.PauseScreen.prototype.resume = function() {
        this.game.add.tween(this).to({alpha: 0}, 300).start().onComplete.add(function() {
            this.game.state.getCurrentState().resume();
        }, this);
    };

    Game.GUI.PauseScreen.prototype.pause = function() {
        this.game.state.getCurrentState().resume();
    };

    Game.GUI.PauseScreen.prototype.toggleMusic = function() {
        this.game.state.getCurrentState().toggleMusic();
        this._refreshMusicBtn();
    };

    Game.GUI.PauseScreen.prototype._refreshMusicBtn = function() {
        this.musicBtn.text = !this.game.musicMuted ? 'Music: on' : 'Music: off';
    };

    Game.GUI.PauseScreen.prototype.toggleFullscreen = function() {
        this.game.state.getCurrentState().toggleFullScreen();
    };

    Game.GUI.PauseScreen.prototype.toggleMultiplayer = function() {
        if (this.game.mpClient) {
            this.game.mpClient.disconnect();
            this.game.mpClient = null;
            this.multiplayerBtn.text = 'Multiplayer:\noff';
        } else {
            if (io) {
                var serverUrl = 'http://{0}:{1}'.format(window.location.hostname, 3001);
                this._createMPClient(serverUrl);
                this.multiplayerBtn.text = 'Multiplayer:\non';
            }
        }
    };

    Game.GUI.PauseScreen.prototype._createMPClient = function(url) {
        this.game.mpClient = new Game.MPClient(this.game, url);
    };

})();
<|endoftext|>


<commit_before>/**
 * Module dependencies
 */

var _ = require('lodash')
	, util = require('util');

/**
 *
 * @param  {[type]} scope [description]
 * @return {[type]}       [description]
 */
module.exports = function dataForPackageJSON (scope) {

	var sailsPkg = scope.sailsPackageJSON || {};

	// To determine the sails dep. to inject in the newly created package.json,
	// use sails.prerelease in package.json. If not specified, just use `version`
	var sailsVersionDependency = (sailsPkg.sails && sailsPkg.sails.prerelease) || ('~' + sailsPkg.version);

	return _.defaults(scope.appPackageJSON || {}, {
		name: scope.appName,
		private: true,
		version: '0.0.0',
		description: 'a Sails application',
		keywords: [],
		dependencies: {
			'sails'     : sailsVersionDependency,
			'sails-disk': getDependencyVersion(sailsPkg, 'sails-disk'),
			'rc'        : getDependencyVersion(sailsPkg, 'rc'),
			'ejs'       : getDependencyVersion(sailsPkg, 'ejs'),
			'grunt'     : getDependencyVersion(sailsPkg, 'grunt'),
			'grunt-sync': getDependencyVersion(sailsPkg, 'grunt-sync'),
			'grunt-contrib-copy': getDependencyVersion(sailsPkg, 'grunt-contrib-copy'),
			'grunt-contrib-clean': getDependencyVersion(sailsPkg, 'grunt-contrib-clean'),
			'grunt-contrib-concat': getDependencyVersion(sailsPkg, 'grunt-contrib-concat'),
			'grunt-sails-linker': getDependencyVersion(sailsPkg, 'grunt-sails-linker'),
			'grunt-contrib-jst': getDependencyVersion(sailsPkg, 'grunt-contrib-jst'),
			'grunt-contrib-watch': getDependencyVersion(sailsPkg, 'grunt-contrib-watch'),
			'grunt-contrib-uglify': getDependencyVersion(sailsPkg, 'grunt-contrib-uglify'),
			'grunt-contrib-cssmin': getDependencyVersion(sailsPkg, 'grunt-contrib-cssmin'),
			'grunt-contrib-less': getDependencyVersion(sailsPkg, 'grunt-contrib-less'),
			'grunt-contrib-coffee': getDependencyVersion(sailsPkg, 'grunt-contrib-coffee')
		},
		scripts: {
			start: 'node app.js',
			debug: 'node debug app.js'
		},
		main: 'app.js',
		repository: {
			type: 'git',
			url: util.format('git://github.com/%s/%s.git', scope.github.username, scope.appName)
		},
		author: scope.author || '',
		license: ''
	});
};

/**
 * getDependencyVersion
 *
 * @param  {Object} packageJSON
 * @param  {String} module
 * @return {String}
 * @api private
 */

function getDependencyVersion (packageJSON, module) {
	return (
		packageJSON.dependencies && packageJSON.dependencies[module] ||
		packageJSON.devDependencies && packageJSON.devDependencies[module] ||
		packageJSON.optionalDependencies && packageJSON.optionalDependencies[module]
	);
}
<commit_msg>create symbolic link for include-all dependency after creating a new project for taskrunner's benefit.<commit_after>/**
 * Module dependencies
 */

var _ = require('lodash')
	, util = require('util');

/**
 *
 * @param  {[type]} scope [description]
 * @return {[type]}       [description]
 */
module.exports = function dataForPackageJSON (scope) {

	var sailsPkg = scope.sailsPackageJSON || {};

	// To determine the sails dep. to inject in the newly created package.json,
	// use `sails.prerelease` specified in the package.json of Sails itself.
	// If a `prerelease` version no. is not specified, just use `version`
	var sailsVersionDependency = (sailsPkg.sails && sailsPkg.sails.prerelease) || ('~' + sailsPkg.version);

	return _.defaults(scope.appPackageJSON || {}, {
		name: scope.appName,
		private: true,
		version: '0.0.0',
		description: 'a Sails application',
		keywords: [],
		dependencies: {
			'sails'      : sailsVersionDependency,
			'sails-disk' : getDependencyVersion(sailsPkg, 'sails-disk'),
			'rc'         : getDependencyVersion(sailsPkg, 'rc'),
			'include-all': getDependencyVersion(sailsPkg, 'include-all'),
			'ejs'        : getDependencyVersion(sailsPkg, 'ejs'),
			'grunt'      : getDependencyVersion(sailsPkg, 'grunt'),
			'grunt-sync' : getDependencyVersion(sailsPkg, 'grunt-sync'),
			'grunt-contrib-copy': getDependencyVersion(sailsPkg, 'grunt-contrib-copy'),
			'grunt-contrib-clean': getDependencyVersion(sailsPkg, 'grunt-contrib-clean'),
			'grunt-contrib-concat': getDependencyVersion(sailsPkg, 'grunt-contrib-concat'),
			'grunt-sails-linker': getDependencyVersion(sailsPkg, 'grunt-sails-linker'),
			'grunt-contrib-jst': getDependencyVersion(sailsPkg, 'grunt-contrib-jst'),
			'grunt-contrib-watch': getDependencyVersion(sailsPkg, 'grunt-contrib-watch'),
			'grunt-contrib-uglify': getDependencyVersion(sailsPkg, 'grunt-contrib-uglify'),
			'grunt-contrib-cssmin': getDependencyVersion(sailsPkg, 'grunt-contrib-cssmin'),
			'grunt-contrib-less': getDependencyVersion(sailsPkg, 'grunt-contrib-less'),
			'grunt-contrib-coffee': getDependencyVersion(sailsPkg, 'grunt-contrib-coffee')
		},
		scripts: {
			start: 'node app.js',
			debug: 'node debug app.js'
		},
		main: 'app.js',
		repository: {
			type: 'git',
			url: util.format('git://github.com/%s/%s.git', scope.github.username, scope.appName)
		},
		author: scope.author || '',
		license: ''
	});
};

/**
 * getDependencyVersion
 *
 * @param  {Object} packageJSON
 * @param  {String} module
 * @return {String}
 * @api private
 */

function getDependencyVersion (packageJSON, module) {
	return (
		packageJSON.dependencies && packageJSON.dependencies[module] ||
		packageJSON.devDependencies && packageJSON.devDependencies[module] ||
		packageJSON.optionalDependencies && packageJSON.optionalDependencies[module]
	);
}
<|endoftext|>


<commit_before><script>
  (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
  (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
  m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
  })(window,document,'script','https://www.google-analytics.com/analytics.js','ga');

  ga('create', 'UA-105153165-1', 'auto');
  ga('send', 'pageview');

</script>
<commit_msg>fix google analytics bug<commit_after>(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','https://www.google-analytics.com/analytics.js','ga');

ga('create', 'UA-105153165-1', 'auto');
ga('send', 'pageview');
<|endoftext|>


<commit_before>/*
 * the media view
 *
 */

define(['jquery', 'backbone','app/task/main_view'], function($, Backbone,main_view){

    var canvas = main_view.$el;

    var View = Backbone.View.extend({

        // build element according to simulus
        initialize: function(){

            this.$el
                .addClass('stimulus')
                .attr('data-handle', this.model.handle)     // add data-handle for handeling of mouse/touch interactions
                .css("visibility", "hidden")
                .css(this.model.get('css'))
                .appendTo(canvas);

            this.render();
        },

        // we keep all stimuli appended to the canvas so that the render function can apply to them
        // they shouldn't affect each other because they have absolute positioning
        // we hide and show them using visibility

        render: function(){
            // these are the things that need recalibrating on refresh
            this.size();
            this.place();
            return this;
        },

        show: function(){
            // if this is a gif, reload it before displaying so that the gif is reset
            if (this.options.type === 'image' && this.options.image.indexOf('gif') !== -1){
                // weird IE9 bug that prevents refreshing gifs...
                if(window.ActiveXObject || "ActiveXObject" in window){ // true only in IE
                    this.$el[0].src =  this.options.image + '#' + Math.random();
                } else {
                    this.$el[0].src =  this.options.image;
                }
            }

            this.$el.css("visibility", "visible");
            return this;
        },

        hide: function(){
            this.$el.css("visibility", "hidden");
            return this;
        },

        size: function(){
            var size = this.model.get('size');

            if (size.font_size){
                this.$el.css('font-size', size.font_size);
            }
            // if this is a word, we don't want to set height (it breaks centering)
            if (size.height != 'auto' && this.options.type != 'word') {
                this.$el.height(size.height + '%');
            }
            if (size.width != 'auto'){
                this.$el.width(size.width + '%');
            }

            return this;
        },

        // places the element on the canvas (has to be called after size)
        // @TODO: this is way too complex to be left here, we should probably export this to a seperate file or something
        place: function(){
            // helper function: returns sizes of element;
            function size($elem){
                return {
                    height    : $elem.outerHeight(),
                    width    : $elem.outerWidth()
                };
            }

            var top, bottom, left, right; // will hold the offset for the locations
            var canvasSize = size(canvas);
            var elSize = size(this.$el);
            // get location setting and set center as default
            var location = this.model.get('location') || {};
            if (typeof location.top == 'undefined' && typeof location.bottom == 'undefined') {
                location.top = 'center';
            }
            if (typeof location.left == 'undefined' && typeof location.right == 'undefined') {
                location.right = 'center';
            }

            // set offsets:
            switch (location.top){
                case undefined :
                    /* falls through */
                case 'auto'     : top = 'auto'; break;
                case 'center'    : top = (canvasSize.height - elSize.height)/2; break;
                default            : top = (canvasSize.height * location.top)/100;
            }

            switch (location.bottom){
                case undefined :
                    /* falls through */
                case 'auto'     : bottom = 'auto'; break;
                case 'center'    : bottom = (canvasSize.height - elSize.height)/2; break;
                default            : bottom = (canvasSize.height * (location.bottom))/100;
            }

            switch (location.left){
                case undefined :
                    /* falls through */
                case 'auto'     : left = 'auto'; break;
                case 'center'    : left = (canvasSize.width - elSize.width)/2; break;
                default            : left = (canvasSize.width * location.left)/100;
            }

            switch (location.right){
                case undefined :
                    /* falls through */
                case 'auto'     : right = 'auto'; break;
                case 'center'    : right = (canvasSize.width - elSize.width)/2; break;
                default            : right = (canvasSize.width * (location.right))/100;
            }

            this.$el.css({
                top     : top,
                bottom    : bottom,
                left     : left,
                right     : right
            });
        }

    });

    // Returns the View Constructor
    return View;
});
<commit_msg>another attempt to rectify the gif problem<commit_after>/*
 * the media view
 *
 */

define(['jquery', 'backbone','app/task/main_view'], function($, Backbone,main_view){

    var canvas = main_view.$el;

    var View = Backbone.View.extend({

        // build element according to simulus
        initialize: function(){

            this.$el
                .addClass('stimulus')
                .attr('data-handle', this.model.handle)     // add data-handle for handeling of mouse/touch interactions
                .css("visibility", "hidden")
                .css(this.model.get('css'))
                .appendTo(canvas);

            this.render();
        },

        // we keep all stimuli appended to the canvas so that the render function can apply to them
        // they shouldn't affect each other because they have absolute positioning
        // we hide and show them using visibility

        render: function(){
            // these are the things that need recalibrating on refresh
            this.size();
            this.place();
            return this;
        },

        show: function(){
            // if this is a gif, reload it before displaying so that the gif is reset
            if (this.options.type === 'image' && this.options.image.indexOf('gif') !== -1){
                // weird IE bug that prevents refreshing gifs...
				// also, on IE11 you can't refresh a gif when it is not visibility:visible
                if(window.ActiveXObject || "ActiveXObject" in window){ // true only in IE
                    this.$el.css("visibility", "visible");
					this.$el[0].src =  this.options.image + '#' + Math.random();
                } else {
                    this.$el[0].src =  this.options.image;
					this.$el.css("visibility", "visible");
                }

				return this;
            }

            this.$el.css("visibility", "visible");
            return this;
        },

        hide: function(){
            this.$el.css("visibility", "hidden");
            return this;
        },

        size: function(){
            var size = this.model.get('size');

            if (size.font_size){
                this.$el.css('font-size', size.font_size);
            }
            // if this is a word, we don't want to set height (it breaks centering)
            if (size.height != 'auto' && this.options.type != 'word') {
                this.$el.height(size.height + '%');
            }
            if (size.width != 'auto'){
                this.$el.width(size.width + '%');
            }

            return this;
        },

        // places the element on the canvas (has to be called after size)
        // @TODO: this is way too complex to be left here, we should probably export this to a seperate file or something
        place: function(){
            // helper function: returns sizes of element;
            function size($elem){
                return {
                    height    : $elem.outerHeight(),
                    width    : $elem.outerWidth()
                };
            }

            var top, bottom, left, right; // will hold the offset for the locations
            var canvasSize = size(canvas);
            var elSize = size(this.$el);
            // get location setting and set center as default
            var location = this.model.get('location') || {};
            if (typeof location.top == 'undefined' && typeof location.bottom == 'undefined') {
                location.top = 'center';
            }
            if (typeof location.left == 'undefined' && typeof location.right == 'undefined') {
                location.right = 'center';
            }

            // set offsets:
            switch (location.top){
                case undefined :
                    /* falls through */
                case 'auto'     : top = 'auto'; break;
                case 'center'    : top = (canvasSize.height - elSize.height)/2; break;
                default            : top = (canvasSize.height * location.top)/100;
            }

            switch (location.bottom){
                case undefined :
                    /* falls through */
                case 'auto'     : bottom = 'auto'; break;
                case 'center'    : bottom = (canvasSize.height - elSize.height)/2; break;
                default            : bottom = (canvasSize.height * (location.bottom))/100;
            }

            switch (location.left){
                case undefined :
                    /* falls through */
                case 'auto'     : left = 'auto'; break;
                case 'center'    : left = (canvasSize.width - elSize.width)/2; break;
                default            : left = (canvasSize.width * location.left)/100;
            }

            switch (location.right){
                case undefined :
                    /* falls through */
                case 'auto'     : right = 'auto'; break;
                case 'center'    : right = (canvasSize.width - elSize.width)/2; break;
                default            : right = (canvasSize.width * (location.right))/100;
            }

            this.$el.css({
                top     : top,
                bottom    : bottom,
                left     : left,
                right     : right
            });
        }

    });

    // Returns the View Constructor
    return View;
});
<|endoftext|>


<commit_before>import Ember from 'ember';

var configKeys, configKeysMap, languageConfigKeys;

languageConfigKeys = {
  go: 'Go',
  php: 'PHP',
  node_js: 'Node.js',
  perl: 'Perl',
  perl6: 'Perl6',
  python: 'Python',
  scala: 'Scala',
  smalltalk: 'Smalltalk',
  ruby: 'Ruby',
  d: 'D',
  julia: 'Julia',
  csharp: 'C#',
  mono: 'Mono',
  dart: 'Dart',
  elixir: 'Elixir',
  ghc: 'GHC',
  haxe: 'Haxe',
  jdk: 'JDK',
  rvm: 'Ruby',
  otp_release: 'OTP Release',
  rust: 'Rust',
  c: 'C',
  cpp: 'C++',
  clojure: 'Clojure',
  lein: 'Lein',
  compiler: 'Compiler',
  crystal: 'Crystal',
  osx_image: 'Xcode',
  r: 'R'
};

configKeys = {
  env: 'ENV',
  gemfile: 'Gemfile',
  xcode_sdk: 'Xcode SDK',
  xcode_scheme: 'Xcode Scheme',
  compiler: 'Compiler',
  os: 'OS'
};

configKeysMap = Ember.merge(configKeys, languageConfigKeys);

export default configKeysMap;

export { languageConfigKeys, configKeys };
<commit_msg>show smalltalk config matrix expansion key<commit_after>import Ember from 'ember';

var configKeys, configKeysMap, languageConfigKeys;

languageConfigKeys = {
  go: 'Go',
  php: 'PHP',
  node_js: 'Node.js',
  perl: 'Perl',
  perl6: 'Perl6',
  python: 'Python',
  scala: 'Scala',
  smalltalk: 'Smalltalk',
  smalltalk_config: 'Config',
  ruby: 'Ruby',
  d: 'D',
  julia: 'Julia',
  csharp: 'C#',
  mono: 'Mono',
  dart: 'Dart',
  elixir: 'Elixir',
  ghc: 'GHC',
  haxe: 'Haxe',
  jdk: 'JDK',
  rvm: 'Ruby',
  otp_release: 'OTP Release',
  rust: 'Rust',
  c: 'C',
  cpp: 'C++',
  clojure: 'Clojure',
  lein: 'Lein',
  compiler: 'Compiler',
  crystal: 'Crystal',
  osx_image: 'Xcode',
  r: 'R'
};

configKeys = {
  env: 'ENV',
  gemfile: 'Gemfile',
  xcode_sdk: 'Xcode SDK',
  xcode_scheme: 'Xcode Scheme',
  compiler: 'Compiler',
  os: 'OS'
};

configKeysMap = Ember.merge(configKeys, languageConfigKeys);

export default configKeysMap;

export { languageConfigKeys, configKeys };
<|endoftext|>


<commit_before>var template = document.querySelector('#event-template').innerHTML;
var destination = document.querySelector('.events');

// PRODUCTION URL
// this requires the latest commit hash in the events-data repo (the merge commit from the last PR)
// Can be the short or long version.
var commitHash = "ac06e08";
var prodUrl = "https://cdn.rawgit.com/node-girls/events-data/" + commitHash + "/events.json";

// DEVELOPMENT URL
// To see if your updated events.json is working, set this variable to the name
// of your working branch on the events-data repo (after you've pushed to GitHub)
var yourWorkingBranchName = "";
var devUrl = "https://rawgit.com/node-girls/events-data/" + yourWorkingBranchName + "/events.json";

// LOCAL URL
// Use if you are serving your events-data repo from a local server (e.g. simple-http-server)
var localUrl = ""

var DATA_URL = prodUrl; // change to devUrl or localURL as necessary

var TODAY = moment().format('YYYY-MM-DD');
<commit_msg>connects to updated data<commit_after>var template = document.querySelector('#event-template').innerHTML;
var destination = document.querySelector('.events');

// PRODUCTION URL
// this requires the latest commit hash in the events-data repo (the merge commit from the last PR)
// Can be the short or long version.
var commitHash = "ac06e08";
var prodUrl = "https://cdn.rawgit.com/node-girls/events-data/" + commitHash + "/events.json";

// DEVELOPMENT URL
// To see if your updated events.json is working, set this variable to the name
// of your working branch on the events-data repo (after you've pushed to GitHub)
var yourWorkingBranchName = "";
var devUrl = "https://rawgit.com/node-girls/events-data/" + yourWorkingBranchName + "/events.json";

// LOCAL URL
// Use if you are serving your events-data repo from a local server (e.g. simple-http-server)
var localUrl = "f8b482a"

var DATA_URL = prodUrl; // change to devUrl or localURL as necessary

var TODAY = moment().format('YYYY-MM-DD');
<|endoftext|>


<commit_before>'use strict';

var helpers = require('./helpers');
var stormpath = require('./stormpath');

/**
 * This callback, when called, will simply continue processing the HTTP
 * request.
 *
 * @callback nextCallback
 */

/**
 * Assert that a user is logged into an account before allowing the user to
 * continue.  If the user is not logged in, they will be redirected to the login
 * page.
 *
 * @method
 *
 * @param {Object} req - The http request.
 * @param {Object} res - The http response.
 * @param {nextCallback} next - The callback which is called to continue
 *   processing the request if the user is authenticated.
 */
module.exports.loginRequired = function(req, res, next) {
  if (!req.user || !req.session || !req.session.user) {
    // Wipe req.user, just in case.
    req.user = undefined;

    var url = req.app.get('stormpathLoginUrl') + '?next=' + encodeURIComponent(req.originalUrl.split('?')[0]);
    res.redirect(302, url);
  } else {
    next();
  }
};

/**
 * Assert that a user is a member of one or more groups before allowing the user
 * to continue.  If the user is not logged in, or does not meet the group
 * requirements, they will be redirected to the login page.
 *
 * @method
 *
 * @param {String[]} groups - A list of groups to assert membership in.  Groups
 *   must be specified by group name.
 * @param {Boolean} [all=true] - Should we assert the user is a member of all groups,
 *   or just one?
 *
 * @returns {Function} Returns an express middleware which asserts a user's
 *   group membership, and only allows the user to continue if the assertions
 *   are true.
 */
module.exports.groupsRequired = function(groups, all) {
  all = all === false ? false : true;

  return function(req, res, next) {
    // Ensure the user is logged in.
    if (!req.user || !req.session || !req.session.user) {
      // Wipe req.user, just in case.
      req.user = undefined;

      var url = req.app.get('stormpathLoginUrl') + '?next=' + encodeURIComponent(req.originalUrl.split('?')[0]);
      res.redirect(302, url);

    // If this user must be a member of all groups, we'll ensure that is the
    // case.
    } else {
      var done = groups.length;
      var safe = false;

      req.user.getGroups(function(err, grps) {
        if (err) {
          helpers.render(req.app.get('stormpathUnauthorizedView'), res);
          req.app.get('stormpathLogger').info('Could not fetch user ' + req.user.email + '\'s groups.');
        } else {
          // Iterate through each group on the user's account, checking to see
          // whether or not it's one of the required groups.
          grps.each(function(group, c) {
            if (groups.indexOf(group.name) > -1) {
              if (!all || --done === 0) {
                safe = true;
                next();
              }
            }
            c();
          },
          // If we get here, it means the user didn't meet the requirements,
          // so we'll send them to the login page with the ?next querystring set.
          function() {
            if (!safe) {
              helpers.render(req.app.get('stormpathUnauthorizedView'), res);
              req.app.get('stormpathLogger').info('User ' + req.user.email + ' attempted to access a protected endpoint but did not meet the group check requirements.');
            }
          });
        }
      });
    }
  };
};

/**
 * Assert that a user has specified valid API credentials before allowing them
 * to continue.  If the user's credentials are invalid, a 401 will be returned
 * along with an appropriate error message.
 *
 * @method
 *
 * @param {Object} req - The http request.
 * @param {Object} res - The http response.
 * @param {nextCallback} next - The callback which is called to continue
 *   processing the request if the user is authenticated.
 */
module.exports.apiAuthenticationRequired = function(req, res, next) {
  // Wipe user data in case it was previously set by helpers.getUser().
  req.user = undefined;
  req.permissions = undefined;
  res.locals.user = undefined;
  res.locals.permissions = undefined;

  if (!req.headers.authorization) {
    req.app.get('stormpathLogger').info('User attempted to access a protected API endpoint with invalid credentials.');
    res.status(401).json({ error: 'Invalid API credentials.' });
  } else {
    req.app.get('stormpathApplication').authenticateApiRequest({ request: req }, function(err, authResult) {
      if (err) {
        req.app.get('stormpathLogger').info('Attempted to authenticate a user via the HTTP authorization header, but invalid credentials were supplied.');
        res.status(401).json({ error: 'Invalid API credentials.' });
      } else {
        authResult.getAccount(function(err, account) {
          if (err) {
            req.app.get('stormpathLogger').info('Attempted to retrieve a user\'s account, but this operation failed.');
            res.status(401).json({ error: 'Invalid API credentials.' });
            return;
          }

          helpers.expandAccount(req.app, account, function(err, expandedAccount) {
            if (err) {
              req.app.get('stormpathLogger').info('Attempted to expand a user\'s account, but this operation failed.');
              res.status(401).json({ error: 'Invalid API credentials.' });
              return;
            }

            res.locals.user = expandedAccount;
            res.locals.permissions = authResult.grantedScopes;
            req.user = expandedAccount;
            req.permissions = authResult.grantedScopes;

            return next();
          });
        });
      }
    });
  }
};

/**
 * Assert that a user is logged into an account before allowing the user to
 * continue.  If the user is not logged in, they will be redirected to the login
 * page.  This method allows the user to authenticate ANY WAY THEY WISH, and
 * responds appropriately given the Accept type of the client.  This is useful
 * for SPA type applications.
 *
 * @method
 *
 * @param {Object} req - The http request.
 * @param {Object} res - The http response.
 * @param {nextCallback} next - The callback which is called to continue
 *   processing the request if the user is authenticated.
 */
module.exports.authenticationRequired = function(req, res, next) {
  if (!req.user) {
    req.app.get('stormpathLogger').info('User attempted to access a protected endpoint with invalid credentials.');
    if (req.accepts(['html', 'json']) === 'html') {
      var url = req.app.get('stormpathLoginUrl') + '?next=' + encodeURIComponent(req.originalUrl.split('?')[0]);
      res.redirect(302, url);
    } else {
      res.status(401).json({ error: 'Invalid API credentials.' });
    }
  } else {
    next();
  }
};
<commit_msg>Retains query parameters upon login redirect<commit_after>'use strict';

var helpers = require('./helpers');
var stormpath = require('./stormpath');

/**
 * This callback, when called, will simply continue processing the HTTP
 * request.
 *
 * @callback nextCallback
 */

/**
 * Assert that a user is logged into an account before allowing the user to
 * continue.  If the user is not logged in, they will be redirected to the login
 * page.
 *
 * @method
 *
 * @param {Object} req - The http request.
 * @param {Object} res - The http response.
 * @param {nextCallback} next - The callback which is called to continue
 *   processing the request if the user is authenticated.
 */
module.exports.loginRequired = function(req, res, next) {
  if (!req.user || !req.session || !req.session.user) {
    // Wipe req.user, just in case.
    req.user = undefined;

    var url = req.app.get('stormpathLoginUrl') + '?next=' + encodeURIComponent(req.originalUrl);
    res.redirect(302, url);
  } else {
    next();
  }
};

/**
 * Assert that a user is a member of one or more groups before allowing the user
 * to continue.  If the user is not logged in, or does not meet the group
 * requirements, they will be redirected to the login page.
 *
 * @method
 *
 * @param {String[]} groups - A list of groups to assert membership in.  Groups
 *   must be specified by group name.
 * @param {Boolean} [all=true] - Should we assert the user is a member of all groups,
 *   or just one?
 *
 * @returns {Function} Returns an express middleware which asserts a user's
 *   group membership, and only allows the user to continue if the assertions
 *   are true.
 */
module.exports.groupsRequired = function(groups, all) {
  all = all === false ? false : true;

  return function(req, res, next) {
    // Ensure the user is logged in.
    if (!req.user || !req.session || !req.session.user) {
      // Wipe req.user, just in case.
      req.user = undefined;

      var url = req.app.get('stormpathLoginUrl') + '?next=' + encodeURIComponent(req.originalUrl);
      res.redirect(302, url);

    // If this user must be a member of all groups, we'll ensure that is the
    // case.
    } else {
      var done = groups.length;
      var safe = false;

      req.user.getGroups(function(err, grps) {
        if (err) {
          helpers.render(req.app.get('stormpathUnauthorizedView'), res);
          req.app.get('stormpathLogger').info('Could not fetch user ' + req.user.email + '\'s groups.');
        } else {
          // Iterate through each group on the user's account, checking to see
          // whether or not it's one of the required groups.
          grps.each(function(group, c) {
            if (groups.indexOf(group.name) > -1) {
              if (!all || --done === 0) {
                safe = true;
                next();
              }
            }
            c();
          },
          // If we get here, it means the user didn't meet the requirements,
          // so we'll send them to the login page with the ?next querystring set.
          function() {
            if (!safe) {
              helpers.render(req.app.get('stormpathUnauthorizedView'), res);
              req.app.get('stormpathLogger').info('User ' + req.user.email + ' attempted to access a protected endpoint but did not meet the group check requirements.');
            }
          });
        }
      });
    }
  };
};

/**
 * Assert that a user has specified valid API credentials before allowing them
 * to continue.  If the user's credentials are invalid, a 401 will be returned
 * along with an appropriate error message.
 *
 * @method
 *
 * @param {Object} req - The http request.
 * @param {Object} res - The http response.
 * @param {nextCallback} next - The callback which is called to continue
 *   processing the request if the user is authenticated.
 */
module.exports.apiAuthenticationRequired = function(req, res, next) {
  // Wipe user data in case it was previously set by helpers.getUser().
  req.user = undefined;
  req.permissions = undefined;
  res.locals.user = undefined;
  res.locals.permissions = undefined;

  if (!req.headers.authorization) {
    req.app.get('stormpathLogger').info('User attempted to access a protected API endpoint with invalid credentials.');
    res.status(401).json({ error: 'Invalid API credentials.' });
  } else {
    req.app.get('stormpathApplication').authenticateApiRequest({ request: req }, function(err, authResult) {
      if (err) {
        req.app.get('stormpathLogger').info('Attempted to authenticate a user via the HTTP authorization header, but invalid credentials were supplied.');
        res.status(401).json({ error: 'Invalid API credentials.' });
      } else {
        authResult.getAccount(function(err, account) {
          if (err) {
            req.app.get('stormpathLogger').info('Attempted to retrieve a user\'s account, but this operation failed.');
            res.status(401).json({ error: 'Invalid API credentials.' });
            return;
          }

          helpers.expandAccount(req.app, account, function(err, expandedAccount) {
            if (err) {
              req.app.get('stormpathLogger').info('Attempted to expand a user\'s account, but this operation failed.');
              res.status(401).json({ error: 'Invalid API credentials.' });
              return;
            }

            res.locals.user = expandedAccount;
            res.locals.permissions = authResult.grantedScopes;
            req.user = expandedAccount;
            req.permissions = authResult.grantedScopes;

            return next();
          });
        });
      }
    });
  }
};

/**
 * Assert that a user is logged into an account before allowing the user to
 * continue.  If the user is not logged in, they will be redirected to the login
 * page.  This method allows the user to authenticate ANY WAY THEY WISH, and
 * responds appropriately given the Accept type of the client.  This is useful
 * for SPA type applications.
 *
 * @method
 *
 * @param {Object} req - The http request.
 * @param {Object} res - The http response.
 * @param {nextCallback} next - The callback which is called to continue
 *   processing the request if the user is authenticated.
 */
module.exports.authenticationRequired = function(req, res, next) {
  if (!req.user) {
    req.app.get('stormpathLogger').info('User attempted to access a protected endpoint with invalid credentials.');
    if (req.accepts(['html', 'json']) === 'html') {
      var url = req.app.get('stormpathLoginUrl') + '?next=' + encodeURIComponent(req.originalUrl);
      res.redirect(302, url);
    } else {
      res.status(401).json({ error: 'Invalid API credentials.' });
    }
  } else {
    next();
  }
};
<|endoftext|>


<commit_before>if (BROWSER == "Chrome") {
  var _gaq = _gaq || [];
  _gaq.push(['_setAccount', 'UA-9905766-3']);
  _gaq.push(['_trackPageview']);

  (function() {
    var ga = document.createElement('script');
    ga.type = 'text/javascript';
    ga.async = true;
    ga.src = 'https://ssl.google-analytics.com/ga.js';
    var s = document.getElementsByTagName('script')[0];
    s.parentNode.insertBefore(ga, s);
  })();
}
else if (BROWSER == "Opera") {
  console.log("OPERAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA analytics");
}<commit_msg>Google Analytics file did not need any browser specific code<commit_after>var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-9905766-3']);
_gaq.push(['_trackPageview']);

(function() {
  var ga = document.createElement('script');
  ga.type = 'text/javascript';
  ga.async = true;
  ga.src = 'https://ssl.google-analytics.com/ga.js';
  var s = document.getElementsByTagName('script')[0];
  s.parentNode.insertBefore(ga, s);
})();<|endoftext|>