<commit_before>import utils from "./utils";
import Intersection from "./intersection";
import Zobrist from "./zobrist";

const BoardState = function({ moveNumber, playedPoint, color, pass, blackPassStones, whitePassStones, intersections, blackStonesCaptured, whiteStonesCaptured, capturedPositions, koPoint, boardSize }) {
  this.moveNumber = moveNumber;
  this.playedPoint = playedPoint;
  this.color = color;
  this.pass = pass;
  this.blackPassStones = blackPassStones;
  this.whitePassStones = whitePassStones;
  this.intersections = intersections;
  this.blackStonesCaptured = blackStonesCaptured;
  this.whiteStonesCaptured = whiteStonesCaptured;
  this.capturedPositions = capturedPositions;
  this.koPoint = koPoint;
  this.boardSize = boardSize;
  this._positionHash = Zobrist.hash(boardSize, intersections);

  Object.freeze(this);
};

BoardState.prototype = {
  copyWithAttributes: function(attrs) {
    const retrieveProperties = ({ moveNumber, playedPoint, color, pass, blackPassStones, whitePassStones, intersections, blackStonesCaptured, whiteStonesCaptured, capturedPositions, koPoint, boardSize }) => ({ moveNumber, playedPoint, color, pass, blackPassStones, whitePassStones, intersections, blackStonesCaptured, whiteStonesCaptured, capturedPositions, koPoint, boardSize });
    const existingAttrs = retrieveProperties(this);
    const newAttrs = retrieveProperties(Object.assign(existingAttrs, attrs));

    return new BoardState(newAttrs);
  },

  _capturesFrom: function(y, x, color) {
    const capturedNeighbors = this.neighborsFor(y, x).filter(neighbor => {
      // TODO: this value of 1 is potentially weird.
      // we're checking against the move before the stone we just played
      // where this space is not occupied yet. things should possibly be
      // reworked.
      return !neighbor.isEmpty() && neighbor.value !== color && this.libertiesAt(neighbor.y, neighbor.x) === 1;
    });

    const capturedStones = utils.flatMap(capturedNeighbors, neighbor => this.groupAt(neighbor.y, neighbor.x));

    return utils.unique(capturedStones);
  },

  _updateIntersection: function(intersection, intersections, color) {
    return intersections.map(i => {
      if (i.y === intersection.y && i.x === intersection.x) {
        return new Intersection(i.y, i.x, color);
      } else {
        return i;
      }
    });
  },

  _removeIntersection: function(intersection, intersections) {
    return this._updateIntersection(intersection, intersections, "empty");
  },

  _withoutIntersectionsMatching: function(condition) {
    const newPoints = this.intersections.map(i => {
      if (condition(i)) {
        return new Intersection(i.y, i.x, "empty");
      } else {
        return i;
      }
    });

    return this._withNewPoints(newPoints);
  },

  _withNewPoints: function(newPoints) {
    const newState = new BoardState({
      moveNumber: this.moveNumber,
      playedPoint: this.playedPoint,
      color: this.color,
      pass: this.pass,
      blackPassStones: this.blackPassStones,
      whitePassStones: this.whitePassStones,
      intersections: newPoints,
      blackStonesCaptured: this.blackStonesCaptured,
      whiteStonesCaptured: this.whiteStonesCaptured,
      capturedPositions: this.capturedPositions,
      koPoint: this.koPoint,
      boardSize: this.boardSize
    });

    return newState;
  },

  nextColor: function() {
    if (this.color === "black") {
      return "white";
    } else {
      return "black";
    }
  },

  yCoordinateFor: function(y) {
    return this.boardSize - y;
  },

  xCoordinateFor: function(x) {
    const letters = ["A", "B", "C", "D", "E", "F", "G", "H", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T"];

    return letters[x];
  },

  playPass: function(color) {
    const stateInfo = {
      moveNumber: this.moveNumber + 1,
      playedPoint: null,
      color: color,
      pass: true,
      blackPassStones: this.blackPassStones,
      whitePassStones: this.whitePassStones,
      intersections: this.intersections,
      blackStonesCaptured: this.blackStonesCaptured,
      whiteStonesCaptured: this.whiteStonesCaptured,
      capturedPositions: [],
      koPoint: null,
      boardSize: this.boardSize
    };

    stateInfo[color + "PassStones"] += 1;

    const newState = new BoardState(stateInfo);

    return newState;
  },

  _simpleKoPoint: function() {
    let simpleKoPoint = null;

    if (this.playedPoint) {
      const { y, x } = this.playedPoint;

      if (this.capturedPositions.length === 1 && this.groupAt(y, x).length === 1 && this.inAtari(y, x)) {
        simpleKoPoint = this.capturedPositions[0];
      }
    }

    return simpleKoPoint;
  },

  playAt: function(y, x, playedColor) {
    const capturedPositions = this._capturesFrom(y, x, playedColor);
    let playedPoint = this.intersectionAt(y, x);
    let newPoints = this.intersections;

    capturedPositions.forEach(i => {
      newPoints = this._removeIntersection(i, newPoints);
    });

    newPoints = this._updateIntersection(playedPoint, newPoints, playedColor);

    const newTotalBlackCaptured = this.blackStonesCaptured + (playedColor === "black" ? 0 : capturedPositions.length);
    const newTotalWhiteCaptured = this.whiteStonesCaptured + (playedColor === "white" ? 0 : capturedPositions.length);

    const boardSize = this.boardSize;

    const moveInfo = {
      moveNumber: this.moveNumber + 1,
      playedPoint: playedPoint,
      color: playedColor,
      pass: false,
      blackPassStones: this.blackPassStones,
      whitePassStones: this.whitePassStones,
      intersections: newPoints,
      blackStonesCaptured: newTotalBlackCaptured,
      whiteStonesCaptured: newTotalWhiteCaptured,
      capturedPositions: capturedPositions,
      boardSize: boardSize
    };

    const withPlayedPoint = new BoardState(moveInfo);

    const possibleKoPoint = withPlayedPoint._simpleKoPoint();

    if (possibleKoPoint) {
      moveInfo["koPoint"] = { y: possibleKoPoint.y, x: possibleKoPoint.x };
    } else {
      moveInfo["koPoint"] = null;
    }

    return new BoardState(moveInfo);
  },

  intersectionAt: function(y, x) {
    if (y >= this.boardSize || x >= this.boardSize) {
      throw new Error(`Intersection at (${y}, ${x}) would be outside the board`);
    }

    if (y < 0 || x < 0) {
      throw new Error(`Intersection position cannot be negative, but was given (4, -1)`);
    }

    return this.intersections[y*this.boardSize + x];
  },

  groupAt: function(y, x) {
    const startingPoint = this.intersectionAt(y, x);

    const [group, _] = this.partitionTraverse(startingPoint, neighbor => {
      return neighbor.sameColorAs(startingPoint);
    });

    return group;
  },

  libertiesAt: function(y, x) {
    const point = this.intersectionAt(y, x);

    const emptyPoints = utils.flatMap(this.groupAt(point.y, point.x), groupPoint => {
      return this.neighborsFor(groupPoint.y, groupPoint.x).filter(intersection => intersection.isEmpty());
    });

    return utils.unique(emptyPoints).length;
  },

  inAtari: function(y, x) {
    return this.libertiesAt(y, x) === 1;
  },

  neighborsFor: function(y, x) {
    const neighbors = [];

    if (x > 0) {
      neighbors.push(this.intersectionAt(y, x - 1));
    }

    if (x < (this.boardSize - 1)) {
      neighbors.push(this.intersectionAt(y, x + 1));
    }

    if (y > 0) {
      neighbors.push(this.intersectionAt(y - 1, x));
    }

    if (y < (this.boardSize - 1)) {
      neighbors.push(this.intersectionAt(y + 1, x));
    }

    return neighbors;
  },

  positionSameAs: function(otherState) {
    return this._positionHash === otherState._positionHash && this.intersections.every(point => {
      return point.sameColorAs(otherState.intersectionAt(point.y, point.x));
    });
  },

  // Iterative depth-first search traversal. Start from
  // startingPoint, iteratively follow all neighbors.
  // If inclusionConditionis met for a neighbor, include it
  // otherwise, exclude it. At the end, return two arrays:
  // One for the included neighbors, another for the remaining neighbors.
  partitionTraverse: function(startingPoint, inclusionCondition) {
    let checkedPoints = [];
    let boundaryPoints = [];
    let pointsToCheck = [];

    pointsToCheck.push(startingPoint);

    while (pointsToCheck.length > 0) {
      const point = pointsToCheck.pop();

      if (checkedPoints.indexOf(point) > -1) {
        // skip it, we already checked
      } else {
        checkedPoints.push(point);

        this.neighborsFor(point.y, point.x).forEach(neighbor => {
          if (checkedPoints.indexOf(neighbor) > -1) {
            // skip this neighbor, we already checked it
          } else {
            if (inclusionCondition(neighbor)) {
              pointsToCheck.push(neighbor);
            } else {
              boundaryPoints.push(neighbor);
            }
          }
        });
      }
    }

    return [checkedPoints, utils.unique(boundaryPoints)];
  }
};

BoardState._initialFor = function(boardSize, handicapStones) {
  this._cache = this._cache || {};
  this._cache[boardSize] = this._cache[boardSize] || {};

  if (this._cache[boardSize][handicapStones]) {
    return this._cache[boardSize][handicapStones];
  }

  let emptyPoints = Array.apply(null, Array(boardSize * boardSize));
  emptyPoints = emptyPoints.map((x, i) => {
    return new Intersection(Math.floor(i / boardSize), i % boardSize);
  });

  const hoshiOffset = boardSize > 11 ? 3 : 2;
  const hoshiPoints = {
    topRight:     { y: hoshiOffset,                 x: boardSize - hoshiOffset - 1 },
    bottomLeft:   { y: boardSize - hoshiOffset - 1, x: hoshiOffset },
    bottomRight:  { y: boardSize - hoshiOffset - 1, x: boardSize - hoshiOffset - 1 },
    topLeft:      { y: hoshiOffset,                 x: hoshiOffset },
    middle:       { y: (boardSize + 1)/2 - 1,       x: (boardSize + 1)/2 - 1 },
    middleLeft:   { y: (boardSize + 1)/2 - 1,       x: hoshiOffset },
    middleRight:  { y: (boardSize + 1)/2 - 1,       x: boardSize - hoshiOffset - 1 },
    middleTop:    { y: hoshiOffset,                 x: (boardSize + 1)/2 - 1 },
    middleBottom: { y: boardSize - hoshiOffset - 1, x: (boardSize + 1)/2 - 1 }
  };
  const handicapPlacements = {
    0: [],
    1: [],
    2: [hoshiPoints.topRight, hoshiPoints.bottomLeft],
    3: [hoshiPoints.topRight, hoshiPoints.bottomLeft, hoshiPoints.bottomRight],
    4: [hoshiPoints.topRight, hoshiPoints.bottomLeft, hoshiPoints.bottomRight, hoshiPoints.topLeft],
    5: [hoshiPoints.topRight, hoshiPoints.bottomLeft, hoshiPoints.bottomRight, hoshiPoints.topLeft, hoshiPoints.middle],
    6: [hoshiPoints.topRight, hoshiPoints.bottomLeft, hoshiPoints.bottomRight, hoshiPoints.topLeft, hoshiPoints.middleLeft, hoshiPoints.middleRight],
    7: [hoshiPoints.topRight, hoshiPoints.bottomLeft, hoshiPoints.bottomRight, hoshiPoints.topLeft, hoshiPoints.middleLeft, hoshiPoints.middleRight, hoshiPoints.middle],
    8: [hoshiPoints.topRight, hoshiPoints.bottomLeft, hoshiPoints.bottomRight, hoshiPoints.topLeft, hoshiPoints.middleLeft, hoshiPoints.middleRight, hoshiPoints.middleTop, hoshiPoints.middleBottom],
    9: [hoshiPoints.topRight, hoshiPoints.bottomLeft, hoshiPoints.bottomRight, hoshiPoints.topLeft, hoshiPoints.middleLeft, hoshiPoints.middleRight, hoshiPoints.middleTop, hoshiPoints.middleBottom, hoshiPoints.middle]
  };

  handicapPlacements[handicapStones].forEach(p => {
    emptyPoints[p.y*boardSize + p.x] = new Intersection(p.y, p.x, "black");
  });

  const initialState = new BoardState({
    color: handicapStones > 1 ? "black" : "white",
    moveNumber: 0,
    intersections: Object.freeze(emptyPoints),
    blackStonesCaptured: 0,
    whiteStonesCaptured: 0,
    whitePassStones: 0,
    blackPassStones: 0,
    boardSize: boardSize
  });

  this._cache[boardSize][handicapStones] = initialState;
  return initialState;
};

export default BoardState;
<commit_msg>Stop storing intersections as played points<commit_after>import utils from "./utils";
import Intersection from "./intersection";
import Zobrist from "./zobrist";

const BoardState = function({ moveNumber, playedPoint, color, pass, blackPassStones, whitePassStones, intersections, blackStonesCaptured, whiteStonesCaptured, capturedPositions, koPoint, boardSize }) {
  this.moveNumber = moveNumber;
  this.playedPoint = playedPoint;
  this.color = color;
  this.pass = pass;
  this.blackPassStones = blackPassStones;
  this.whitePassStones = whitePassStones;
  this.intersections = intersections;
  this.blackStonesCaptured = blackStonesCaptured;
  this.whiteStonesCaptured = whiteStonesCaptured;
  this.capturedPositions = capturedPositions;
  this.koPoint = koPoint;
  this.boardSize = boardSize;
  this._positionHash = Zobrist.hash(boardSize, intersections);

  Object.freeze(this);
};

BoardState.prototype = {
  copyWithAttributes: function(attrs) {
    const retrieveProperties = ({ moveNumber, playedPoint, color, pass, blackPassStones, whitePassStones, intersections, blackStonesCaptured, whiteStonesCaptured, capturedPositions, koPoint, boardSize }) => ({ moveNumber, playedPoint, color, pass, blackPassStones, whitePassStones, intersections, blackStonesCaptured, whiteStonesCaptured, capturedPositions, koPoint, boardSize });
    const existingAttrs = retrieveProperties(this);
    const newAttrs = retrieveProperties(Object.assign(existingAttrs, attrs));

    return new BoardState(newAttrs);
  },

  _capturesFrom: function(y, x, color) {
    const capturedNeighbors = this.neighborsFor(y, x).filter(neighbor => {
      // TODO: this value of 1 is potentially weird.
      // we're checking against the move before the stone we just played
      // where this space is not occupied yet. things should possibly be
      // reworked.
      return !neighbor.isEmpty() && neighbor.value !== color && this.libertiesAt(neighbor.y, neighbor.x) === 1;
    });

    const capturedStones = utils.flatMap(capturedNeighbors, neighbor => this.groupAt(neighbor.y, neighbor.x));

    return utils.unique(capturedStones);
  },

  _updateIntersection: function(intersection, intersections, color) {
    return intersections.map(i => {
      if (i.y === intersection.y && i.x === intersection.x) {
        return new Intersection(i.y, i.x, color);
      } else {
        return i;
      }
    });
  },

  _removeIntersection: function(intersection, intersections) {
    return this._updateIntersection(intersection, intersections, "empty");
  },

  _withoutIntersectionsMatching: function(condition) {
    const newPoints = this.intersections.map(i => {
      if (condition(i)) {
        return new Intersection(i.y, i.x, "empty");
      } else {
        return i;
      }
    });

    return this._withNewPoints(newPoints);
  },

  _withNewPoints: function(newPoints) {
    return this.copyWithAttributes({ intersections: newPoints });
  },

  nextColor: function() {
    if (this.color === "black") {
      return "white";
    } else {
      return "black";
    }
  },

  yCoordinateFor: function(y) {
    return this.boardSize - y;
  },

  xCoordinateFor: function(x) {
    const letters = ["A", "B", "C", "D", "E", "F", "G", "H", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T"];

    return letters[x];
  },

  playPass: function(color) {
    const stateInfo = {
      moveNumber: this.moveNumber + 1,
      playedPoint: null,
      color: color,
      pass: true,
      blackPassStones: this.blackPassStones,
      whitePassStones: this.whitePassStones,
      intersections: this.intersections,
      blackStonesCaptured: this.blackStonesCaptured,
      whiteStonesCaptured: this.whiteStonesCaptured,
      capturedPositions: [],
      koPoint: null,
      boardSize: this.boardSize
    };

    stateInfo[color + "PassStones"] += 1;

    const newState = new BoardState(stateInfo);

    return newState;
  },

  _simpleKoPoint: function() {
    let simpleKoPoint = null;

    if (this.playedPoint) {
      const { y, x } = this.playedPoint;

      if (this.capturedPositions.length === 1 && this.groupAt(y, x).length === 1 && this.inAtari(y, x)) {
        simpleKoPoint = this.capturedPositions[0];
      }
    }

    return simpleKoPoint;
  },

  playAt: function(y, x, playedColor) {
    const capturedPositions = this._capturesFrom(y, x, playedColor);
    let playedPoint = this.intersectionAt(y, x);
    let newPoints = this.intersections;

    capturedPositions.forEach(i => {
      newPoints = this._removeIntersection(i, newPoints);
    });

    newPoints = this._updateIntersection(playedPoint, newPoints, playedColor);

    const newTotalBlackCaptured = this.blackStonesCaptured + (playedColor === "black" ? 0 : capturedPositions.length);
    const newTotalWhiteCaptured = this.whiteStonesCaptured + (playedColor === "white" ? 0 : capturedPositions.length);

    const boardSize = this.boardSize;

    const moveInfo = {
      moveNumber: this.moveNumber + 1,
      playedPoint: Object.freeze({ y, x }),
      color: playedColor,
      pass: false,
      blackPassStones: this.blackPassStones,
      whitePassStones: this.whitePassStones,
      intersections: newPoints,
      blackStonesCaptured: newTotalBlackCaptured,
      whiteStonesCaptured: newTotalWhiteCaptured,
      capturedPositions: capturedPositions,
      boardSize: boardSize
    };

    const withPlayedPoint = new BoardState(moveInfo);

    const possibleKoPoint = withPlayedPoint._simpleKoPoint();

    if (possibleKoPoint) {
      moveInfo["koPoint"] = { y: possibleKoPoint.y, x: possibleKoPoint.x };
    } else {
      moveInfo["koPoint"] = null;
    }

    return new BoardState(moveInfo);
  },

  intersectionAt: function(y, x) {
    if (y >= this.boardSize || x >= this.boardSize) {
      throw new Error(`Intersection at (${y}, ${x}) would be outside the board`);
    }

    if (y < 0 || x < 0) {
      throw new Error(`Intersection position cannot be negative, but was given (4, -1)`);
    }

    return this.intersections[y*this.boardSize + x];
  },

  groupAt: function(y, x) {
    const startingPoint = this.intersectionAt(y, x);

    const [group, _] = this.partitionTraverse(startingPoint, neighbor => {
      return neighbor.sameColorAs(startingPoint);
    });

    return group;
  },

  libertiesAt: function(y, x) {
    const point = this.intersectionAt(y, x);

    const emptyPoints = utils.flatMap(this.groupAt(point.y, point.x), groupPoint => {
      return this.neighborsFor(groupPoint.y, groupPoint.x).filter(intersection => intersection.isEmpty());
    });

    return utils.unique(emptyPoints).length;
  },

  inAtari: function(y, x) {
    return this.libertiesAt(y, x) === 1;
  },

  neighborsFor: function(y, x) {
    const neighbors = [];

    if (x > 0) {
      neighbors.push(this.intersectionAt(y, x - 1));
    }

    if (x < (this.boardSize - 1)) {
      neighbors.push(this.intersectionAt(y, x + 1));
    }

    if (y > 0) {
      neighbors.push(this.intersectionAt(y - 1, x));
    }

    if (y < (this.boardSize - 1)) {
      neighbors.push(this.intersectionAt(y + 1, x));
    }

    return neighbors;
  },

  positionSameAs: function(otherState) {
    return this._positionHash === otherState._positionHash && this.intersections.every(point => {
      return point.sameColorAs(otherState.intersectionAt(point.y, point.x));
    });
  },

  // Iterative depth-first search traversal. Start from
  // startingPoint, iteratively follow all neighbors.
  // If inclusionConditionis met for a neighbor, include it
  // otherwise, exclude it. At the end, return two arrays:
  // One for the included neighbors, another for the remaining neighbors.
  partitionTraverse: function(startingPoint, inclusionCondition) {
    let checkedPoints = [];
    let boundaryPoints = [];
    let pointsToCheck = [];

    pointsToCheck.push(startingPoint);

    while (pointsToCheck.length > 0) {
      const point = pointsToCheck.pop();

      if (checkedPoints.indexOf(point) > -1) {
        // skip it, we already checked
      } else {
        checkedPoints.push(point);

        this.neighborsFor(point.y, point.x).forEach(neighbor => {
          if (checkedPoints.indexOf(neighbor) > -1) {
            // skip this neighbor, we already checked it
          } else {
            if (inclusionCondition(neighbor)) {
              pointsToCheck.push(neighbor);
            } else {
              boundaryPoints.push(neighbor);
            }
          }
        });
      }
    }

    return [checkedPoints, utils.unique(boundaryPoints)];
  }
};

BoardState._initialFor = function(boardSize, handicapStones) {
  this._cache = this._cache || {};
  this._cache[boardSize] = this._cache[boardSize] || {};

  if (this._cache[boardSize][handicapStones]) {
    return this._cache[boardSize][handicapStones];
  }

  let emptyPoints = Array.apply(null, Array(boardSize * boardSize));
  emptyPoints = emptyPoints.map((x, i) => {
    return new Intersection(Math.floor(i / boardSize), i % boardSize);
  });

  const hoshiOffset = boardSize > 11 ? 3 : 2;
  const hoshiPoints = {
    topRight:     { y: hoshiOffset,                 x: boardSize - hoshiOffset - 1 },
    bottomLeft:   { y: boardSize - hoshiOffset - 1, x: hoshiOffset },
    bottomRight:  { y: boardSize - hoshiOffset - 1, x: boardSize - hoshiOffset - 1 },
    topLeft:      { y: hoshiOffset,                 x: hoshiOffset },
    middle:       { y: (boardSize + 1)/2 - 1,       x: (boardSize + 1)/2 - 1 },
    middleLeft:   { y: (boardSize + 1)/2 - 1,       x: hoshiOffset },
    middleRight:  { y: (boardSize + 1)/2 - 1,       x: boardSize - hoshiOffset - 1 },
    middleTop:    { y: hoshiOffset,                 x: (boardSize + 1)/2 - 1 },
    middleBottom: { y: boardSize - hoshiOffset - 1, x: (boardSize + 1)/2 - 1 }
  };
  const handicapPlacements = {
    0: [],
    1: [],
    2: [hoshiPoints.topRight, hoshiPoints.bottomLeft],
    3: [hoshiPoints.topRight, hoshiPoints.bottomLeft, hoshiPoints.bottomRight],
    4: [hoshiPoints.topRight, hoshiPoints.bottomLeft, hoshiPoints.bottomRight, hoshiPoints.topLeft],
    5: [hoshiPoints.topRight, hoshiPoints.bottomLeft, hoshiPoints.bottomRight, hoshiPoints.topLeft, hoshiPoints.middle],
    6: [hoshiPoints.topRight, hoshiPoints.bottomLeft, hoshiPoints.bottomRight, hoshiPoints.topLeft, hoshiPoints.middleLeft, hoshiPoints.middleRight],
    7: [hoshiPoints.topRight, hoshiPoints.bottomLeft, hoshiPoints.bottomRight, hoshiPoints.topLeft, hoshiPoints.middleLeft, hoshiPoints.middleRight, hoshiPoints.middle],
    8: [hoshiPoints.topRight, hoshiPoints.bottomLeft, hoshiPoints.bottomRight, hoshiPoints.topLeft, hoshiPoints.middleLeft, hoshiPoints.middleRight, hoshiPoints.middleTop, hoshiPoints.middleBottom],
    9: [hoshiPoints.topRight, hoshiPoints.bottomLeft, hoshiPoints.bottomRight, hoshiPoints.topLeft, hoshiPoints.middleLeft, hoshiPoints.middleRight, hoshiPoints.middleTop, hoshiPoints.middleBottom, hoshiPoints.middle]
  };

  handicapPlacements[handicapStones].forEach(p => {
    emptyPoints[p.y*boardSize + p.x] = new Intersection(p.y, p.x, "black");
  });

  const initialState = new BoardState({
    color: handicapStones > 1 ? "black" : "white",
    moveNumber: 0,
    intersections: Object.freeze(emptyPoints),
    blackStonesCaptured: 0,
    whiteStonesCaptured: 0,
    whitePassStones: 0,
    blackPassStones: 0,
    boardSize: boardSize
  });

  this._cache[boardSize][handicapStones] = initialState;
  return initialState;
};

export default BoardState;
<|endoftext|>


<commit_before>var app = angular.module('app', [],
    function ($interpolateProvider) {
        $interpolateProvider.startSymbol('[[');
        $interpolateProvider.endSymbol(']]');
    });

app.filter('escape', function () {
    return window.encodeURIComponent;
});

app.controller('resultsCtrl', ['$http', '$rootScope', '$scope', function ($http, $rootScope, $scope) {

    $scope.results = [];

    var getMoreResults = true;

    var request = {
        method: 'GET',
        url: 'results.json',
        params: {
            start: -25,
            limit: 25,
            q: $scope.q,
            facet: true
        }
    };

    getResults(request);

    $(window).scroll(function () {
        if (getMoreResults) {
            if ($(window).scrollTop() + $(window).height() == $(document).height()) {
                getResults(request);
            }
        }
    });

    $scope.$on('filters', function (event, filters) {
        //delete request.params.facet;
        request.params.filters = filters;
        request.params.start = 0;
        getResults(request);
    });

    function getResults(request) {
        request.params.start = request.params.start + request.params.limit;
        $http(request).then(function (response) {
            var data = response.data;
            if (data.count > 0) {
                if (request.params.start === 0) {
                    $scope.results = data.data;
                } else {
                    $scope.results = $scope.results.concat(data.data);
                }
                if (request.params.facet) {
                    $rootScope.$broadcast('columns', data.facets);
                }
            } else {
                getMoreResults = false;
            }
        }, function (response) {
            console.debug(response);
        });
    }
}]).controller('facetsCtrl', ['$rootScope', '$scope', function ($rootScope, $scope) {
    $scope.columns = [];
    $scope.filters = {};

    $scope.$on('columns', function (event, columns) {
        $scope.columns = columns;
    });

    $scope.toggleFilter = function (column, facet) {
        if (!$scope.filters[column]) {
            $scope.filters[column] = [];
        }
        var index = $scope.filters[column].indexOf(facet);

        if (index !== -1) {
            $scope.filters[column].splice(index, 1);
            if ($scope.filters[column].length == 0) {
                delete $scope.filters[column];
            }
        } else {
            $scope.filters[column].push(facet);
        }
        $rootScope.$broadcast('filters', $scope.filters);
    };
}]);<commit_msg>Changed results function<commit_after>var app = angular.module('app', [],
    function ($interpolateProvider) {
        $interpolateProvider.startSymbol('[[');
        $interpolateProvider.endSymbol(']]');
    });

app.filter('escape', function () {
    return window.encodeURIComponent;
});

app.controller('resultsCtrl', ['$http', '$rootScope', '$scope', function ($http, $rootScope, $scope) {

    $scope.results = [];

    var getMoreResults = true;

    var request = {
        method: 'GET',
        url: 'results.json',
        params: {
            start: 0,
            limit: 25,
            q: $scope.q,
            facet: true
        }
    };

    getResults(request);

    $(window).scroll(function () {
        if (getMoreResults) {
            if ($(window).scrollTop() + $(window).height() == $(document).height()) {
                getResults(request);
            }
        }
    });

    $scope.$on('filters', function (event, filters) {
        //delete request.params.facet;
        request.params.filters = filters;
        request.params.start = 0;
        getResults(request);
    });

    function getResults(request) {
        $http(request).then(function (response) {
            request.params.start = request.params.start + request.params.limit;
            var data = response.data;
            if (data.count > 0) {
                if (request.params.start === 0) {
                    $scope.results = data.data;
                } else {
                    $scope.results = $scope.results.concat(data.data);
                }
                if (request.params.facet) {
                    $rootScope.$broadcast('columns', data.facets);
                }
            } else {
                getMoreResults = false;
            }
        }, function (response) {
            console.debug(response);
        });
    }
}]).controller('facetsCtrl', ['$rootScope', '$scope', function ($rootScope, $scope) {
    $scope.columns = [];
    $scope.filters = {};

    $scope.$on('columns', function (event, columns) {
        $scope.columns = columns;
    });

    $scope.toggleFilter = function (column, facet) {
        if (!$scope.filters[column]) {
            $scope.filters[column] = [];
        }
        var index = $scope.filters[column].indexOf(facet);

        if (index !== -1) {
            $scope.filters[column].splice(index, 1);
            if ($scope.filters[column].length == 0) {
                delete $scope.filters[column];
            }
        } else {
            $scope.filters[column].push(facet);
        }
        $rootScope.$broadcast('filters', $scope.filters);
    };
}]);<|endoftext|>


<commit_before>/*var showStep = function() {
  $('#product-info').children().removeClass('show');
  $('#product-info').children(':nth-child(' + Session.get('postState') + ')').addClass('show');
  }
  */

var verifyField = function(a) {
    var b = a.find('input, select').val();
    return (b != undefined && b != '') || Session.get('postState') == 5;
}

//The following code will take care of verfying and submitting all of the posts, when I care to finish writing it.
Template.addTitle.rendered = function(){
    $('form').submit(function(e) {
	e.preventDefault();
        var temp;
        if(Session.get('tempProdForm'))
	    temp = Session.get('tempProdForm');
	temp.title = $('input[name=title]').val();
	Session.set('tempProdForm',temp);
	Router.go('/sell/info');
    });
}

//should i put all of this code in it's own stuff hm
Template.addInfo.rendered = function() {
    //maybe i should take care of this by hiding the div instead of having different routes
    if(Session.get('tempProdForm')) {
        temp = Session.get('tempProdForm');
        //nm use helpers HERE
    }
    $('#b_pNext').click(function(e) {
        e.preventDefault();
        temp = Session.get('tempProdForm');
        temp.title = $('input[name=title]').val();
	temp.category = $('input[name=category]').val();
	temp.so = $('input[name=so]').val();
	temp.bin = $('input[name=bin]').val();
	temp.condition = $('select[name=condition]').val();
	temp.description = $('#description').html();
        console.log(temp);
        Session.set('tempProdForm', temp);
        Router.go('/sell/preview');
    });
}

Template.postPreview.rendered = function(){
    $('#addProdBut').click(function(e) {
	e.preventDefault();
	console.log("adding item");
	Meteor.call('addProduct', Session.get('tempProdForm'), function(e,r) {
	    console.log("something");
	    if(e) {
		alert(e);
	    }else{
		console.log("done");
		Router.go('/post/' + r);
	    }
	});
    });
}

Template.pageAddProduct.rendered = function(){
    if(!Session.get('tempProdForm'))
	Session.set('tempProdForm',{});
};

Template.postPreview.helpers({
    'title': function() {
	if(Session.get('tempProdForm'))
    return Session.get('tempProdForm').title;
    },
    'category': function() {
	if(Session.get('tempProdForm'))
    return Session.get('tempProdForm').category;
//return $('[name=category]').val();
    },
    'so': function() {
	if(Session.get('tempProdForm'))
    return Session.get('tempProdForm').so;
//return $('[name=so]').val();
    },
    'bin': function() {
	if(Session.get('tempProdForm'))
    return Session.get('tempProdForm').bin;
//return $('[name=bin]').val();
    },
    'condition': function() {
	if(Session.get('tempProdForm'))
	    return Session.get('tempProdForm').condition;
	//return $('[name=condition]').val();
    },
    'description': function() {
	if(Session.get('tempProdForm'))
	    return Session.get('tempProdForm').description;
	//return $('#itemDescription').html();
    },
});
<commit_msg>steps changing color test 1<commit_after>/*var showStep = function() {
  $('#product-info').children().removeClass('show');
  $('#product-info').children(':nth-child(' + Session.get('postState') + ')').addClass('show');
  }
  */

var verifyField = function(a) {
    var b = a.find('input, select').val();
    return (b != undefined && b != '') || Session.get('postState') == 5;
}

var changeStep = function(i) {
    $('.step-circle')[i-1].removeClass('active');
    $('.step-circle')[i-1].addClass('complete');
    $('.step-circle')[i].addClass('active');
}

//The following code will take care of verfying and submitting all of the posts, when I care to finish writing it.
Template.addTitle.rendered = function(){
    $('form').submit(function(e) {
	e.preventDefault();
        var temp;
        if(Session.get('tempProdForm'))
	    temp = Session.get('tempProdForm');
	temp.title = $('input[name=title]').val();
        changeStep(1);
	Session.set('tempProdForm',temp);
	Router.go('/sell/info');
    });
}

//should i put all of this code in it's own stuff hm
Template.addInfo.rendered = function() {
    //maybe i should take care of this by hiding the div instead of having different routes
    if(Session.get('tempProdForm')) {
        temp = Session.get('tempProdForm');
        //nm use helpers HERE
    }
    $('#b_pNext').click(function(e) {
        e.preventDefault();
        changeStep(2);
        temp = Session.get('tempProdForm');
        temp.title = $('input[name=title]').val();
	temp.category = $('input[name=category]').val();
	temp.so = $('input[name=so]').val();
	temp.bin = $('input[name=bin]').val();
	temp.condition = $('select[name=condition]').val();
	temp.description = $('#description').html();
        console.log(temp);
        Session.set('tempProdForm', temp);
        Router.go('/sell/preview');
    });
}

Template.postPreview.rendered = function(){
    $('#addProdBut').click(function(e) {
	e.preventDefault();
	console.log("adding item");
	Meteor.call('addProduct', Session.get('tempProdForm'), function(e,r) {
	    console.log("something");
	    if(e) {
		alert(e);
	    }else{
		console.log("done");
		Router.go('/post/' + r);
	    }
	});
    });
}

Template.pageAddProduct.rendered = function(){
    if(!Session.get('tempProdForm'))
	Session.set('tempProdForm',{});
};

Template.postPreview.helpers({
    'title': function() {
	if(Session.get('tempProdForm'))
    return Session.get('tempProdForm').title;
    },
    'category': function() {
	if(Session.get('tempProdForm'))
    return Session.get('tempProdForm').category;
//return $('[name=category]').val();
    },
    'so': function() {
	if(Session.get('tempProdForm'))
    return Session.get('tempProdForm').so;
//return $('[name=so]').val();
    },
    'bin': function() {
	if(Session.get('tempProdForm'))
    return Session.get('tempProdForm').bin;
//return $('[name=bin]').val();
    },
    'condition': function() {
	if(Session.get('tempProdForm'))
	    return Session.get('tempProdForm').condition;
	//return $('[name=condition]').val();
    },
    'description': function() {
	if(Session.get('tempProdForm'))
	    return Session.get('tempProdForm').description;
	//return $('#itemDescription').html();
    },
});
<|endoftext|>


<commit_before>"use strict"

var Promise = require('./util').Promise,
  AggregationCursor = require('./aggregation_cursor'),
  Cursor = require('./cursor');

class Collection {
  constructor(name, db) {
    this.name = name;
    this.db = db;
    this.namespace = db.name + "." + name;
  }

  /**
   * Inserts a single document into MongoDB. If documents passed in do not contain the **_id** field,
   * one will be added to each of the documents missing it by the driver, mutating the document. This behavior
   * can be overridden by setting the **forceServerObjectId** flag.
   *
   * @method
   * @param {object} doc Document to insert.
   * @param {object} [options=null] Optional settings.
   * @param {boolean} [options.bypassDocumentValidation=false] Allow driver to bypass schema validation in MongoDB 3.2 or higher.
   * @param {string|number} [options.w=null] Write concern for the write operation.
   * @param {boolean} [options.j=null] Wait for journal flush on write.
   * @param {number} [options.wtimeout=null] Write concern timeout.
   * @return {Promise} returns Promise
   */
  insertOne(document, options) {
    return this.db.command(Object.assign({
        insertOne: this.namespace,
        doc: document,
      }, options || {})
    );
  }

  /**
   * Inserts an array of documents into MongoDB. If documents passed in do not contain the **_id** field,
   * one will be added to each of the documents missing it by the driver, mutating the document. This behavior
   * can be overridden by setting the **forceServerObjectId** flag.
   *
   * @method
   * @param {object[]} docs Documents to insert.
   * @param {object} [options=null] Optional settings.
   * @param {boolean} [options.ordered=true] Execute write operation in ordered or unordered fashion.
   * @param {boolean} [options.bypassDocumentValidation=false] Allow driver to bypass schema validation in MongoDB 3.2 or higher.
   * @param {string|number} [options.w=null] Write concern for the write operation.
   * @param {boolean} [options.j=null] Wait for journal flush on write.
   * @param {number} [options.wtimeout=null] Write concern timeout.
   * @return {Promise} returns Promise
   */
  insertMany(documents, options) {
    return this.db.command(Object.assign({
        insertMany: this.namespace,
        docs: documents,
      }, options || {})
    );
  }

  /**
   * Update a single document on MongoDB
   * @method
   * @param {object} filter The Filter used to select the document to update
   * @param {object} update The update operations to be applied to the document
   * @param {object} [options=null] Optional settings.
   * @param {boolean} [options.upsert=false] Update operation is an upsert.
   * @param {boolean} [options.bypassDocumentValidation=false] Allow driver to bypass schema validation in MongoDB 3.2 or higher.
   * @param {string|number} [options.w=null] Write concern for the write operation.
   * @param {boolean} [options.j=null] Wait for journal flush on write.
   * @param {number} [options.wtimeout=null] Write concern timeout.
   * @return {Promise} returns Promise
   */
  updateOne(filter, update, options) {
    return this.db.command(Object.assign({
        updateOne: this.namespace,
        q: filter,
        u: update
      }, options || {})
    );
  }

  /**
   * Update multiple documents on MongoDB
   * @method
   * @param {object} filter The Filter used to select the document to update
   * @param {object} update The update operations to be applied to the document
   * @param {object} [options=null] Optional settings.
   * @param {boolean} [options.upsert=false] Update operation is an upsert.
   * @param {boolean} [options.bypassDocumentValidation=false] Allow driver to bypass schema validation in MongoDB 3.2 or higher.
   * @param {string|number} [options.w=null] Write concern for the write operation.
   * @param {boolean} [options.j=null] Wait for journal flush on write.
   * @param {number} [options.wtimeout=null] Write concern timeout.
   * @return {Promise} returns Promise
   */
  updateMany(filter, update, options) {
    return this.db.command(Object.assign({
        updateMany: this.namespace,
        q: filter,
        u: update
      }, options || {})
    );
  }

  /**
   * Replace a document on MongoDB
   * @method
   * @param {object} filter The Filter used to select the document to update
   * @param {object} doc The Document that replaces the matching document
   * @param {object} [options=null] Optional settings.
   * @param {boolean} [options.upsert=false] Update operation is an upsert.
   * @param {boolean} [options.bypassDocumentValidation=false] Allow driver to bypass schema validation in MongoDB 3.2 or higher.
   * @param {string|number} [options.w=null] Write concern for the write operation.
   * @param {boolean} [options.j=null] Wait for journal flush on write.
   * @param {number} [options.wtimeout=null] Write concern timeout.
   * @return {Promise} returns Promise
   */
  replaceOne(filter, doc, options) {
    return this.db.command(Object.assign({
        replaceOne: this.namespace,
        q: filter,
        u: doc
      }, options || {})
    );
  }

  /**
   * Delete a document on MongoDB
   * @method
   * @param {object} filter The Filter used to select the document to remove
   * @param {object} [options=null] Optional settings.
   * @param {string|number} [options.w=null] Write concern for the write operation.
   * @param {boolean} [options.j=null] Wait for journal flush on write.
   * @param {number} [options.wtimeout=null] Write concern timeout.
   * @return {Promise} returns Promise
   */
  deleteOne(filter, options) {
    return this.db.command(Object.assign({
        deleteOne: this.namespace,
        q: filter,
      }, options || {})
    );
  }

  /**
   * Delete multiple documents on MongoDB
   * @method
   * @param {object} filter The Filter used to select the documents to remove
   * @param {object} [options=null] Optional settings.
   * @param {string|number} [options.w=null] Write concern for the write operation.
   * @param {boolean} [options.j=null] Wait for journal flush on write.
   * @param {number} [options.wtimeout=null] Write concern timeout.
   * @return {Promise} returns Promise
   */
  deleteMany(filter, options) {
    return this.db.command(Object.assign({
        deleteMany: this.namespace,
        q: filter,
      }, options || {})
    );
  }

  /**
   * Find a document and delete it in one atomic operation, requires a write lock for the duration of the operation.
   *
   * @method
   * @param {object} filter Document selection filter.
   * @param {object} [options=null] Optional settings.
   * @param {object} [options.projection=null] Limits the fields to return for all matching documents.
   * @param {object} [options.sort=null] Determines which document the operation modifies if the query selects multiple documents.
   * @param {number} [options.maxTimeMS=null] The maximum amount of time to allow the query to run.
   * @param {string|number} [options.w=null] Write concern for the write operation.
   * @param {boolean} [options.j=null] Wait for journal flush on write.
   * @param {number} [options.wtimeout=null] Write concern timeout.
   * @param {boolean} [options.bypassDocumentValidation=false] Allow driver to bypass schema validation in MongoDB 3.2 or higher.
   * @return {Promise} returns Promise
   */
  findOneAndDelete(filter, options) {
    return this.db.command(Object.assign({
        findOneAndDelete: this.namespace,
        q: filter,
      }, options || {})
    );
  }

  /**
   * Find a document and update it in one atomic operation, requires a write lock for the duration of the operation.
   *
   * @method
   * @param {object} filter Document selection filter.
   * @param {object} update Update operations to be performed on the document
   * @param {object} [options=null] Optional settings.
   * @param {object} [options.projection=null] Limits the fields to return for all matching documents.
   * @param {object} [options.sort=null] Determines which document the operation modifies if the query selects multiple documents.
   * @param {number} [options.maxTimeMS=null] The maximum amount of time to allow the query to run.
   * @param {boolean} [options.upsert=false] Upsert the document if it does not exist.
   * @param {boolean} [options.returnOriginal=true] When false, returns the updated document rather than the original. The default is true.
   * @param {string|number} [options.w=null] Write concern for the write operation.
   * @param {boolean} [options.j=null] Wait for journal flush on write.
   * @param {number} [options.wtimeout=null] Write concern timeout.
   * @param {boolean} [options.bypassDocumentValidation=false] Allow driver to bypass schema validation in MongoDB 3.2 or higher.
   * @return {Promise} returns Promise
   */
  findOneAndUpdate(filter, update, options) {
    return this.db.command(Object.assign({
        findOneAndUpdate: this.namespace,
        q: filter,
        u: update
      }, options || {})
    );
  }

  /**
   * Find a document and replace it in one atomic operation, requires a write lock for the duration of the operation.
   *
   * @method
   * @param {object} filter Document selection filter.
   * @param {object} replacement Document replacing the matching document.
   * @param {object} [options=null] Optional settings.
   * @param {object} [options.projection=null] Limits the fields to return for all matching documents.
   * @param {object} [options.sort=null] Determines which document the operation modifies if the query selects multiple documents.
   * @param {number} [options.maxTimeMS=null] The maximum amount of time to allow the query to run.
   * @param {boolean} [options.upsert=false] Upsert the document if it does not exist.
   * @param {boolean} [options.returnOriginal=true] When false, returns the updated document rather than the original. The default is true.
   * @param {string|number} [options.w=null] Write concern for the write operation.
   * @param {boolean} [options.j=null] Wait for journal flush on write.
   * @param {number} [options.wtimeout=null] Write concern timeout.
   * @param {boolean} [options.bypassDocumentValidation=false] Allow driver to bypass schema validation in MongoDB 3.2 or higher.
   * @return {Promise} returns Promise
   */
  findOneAndReplace(filter, replace, options) {
    return this.db.command(Object.assign({
        findOneAndReplace: this.namespace,
        q: filter,
        u: replace
      }, options || {})
    );
  }

  /**
   * Perform a bulkWrite operation without a fluent API
   *
   * Legal operation types are
   *
   *  { insertOne: { document: { a: 1 } } }
   *
   *  { updateOne: { filter: {a:2}, update: {$set: {a:2}}, upsert:true } }
   *
   *  { updateMany: { filter: {a:2}, update: {$set: {a:2}}, upsert:true } }
   *
   *  { deleteOne: { filter: {c:1} } }
   *
   *  { deleteMany: { filter: {c:1} } }
   *
   *  { replaceOne: { filter: {c:3}, replacement: {c:4}, upsert:true}}
   *
   * If documents passed in do not contain the **_id** field,
   * one will be added to each of the documents missing it by the driver, mutating the document. This behavior
   * can be overridden by setting the **forceServerObjectId** flag.
   *
   * @method
   * @param {object[]} operations Bulk operations to perform.
   * @param {object} [options=null] Optional settings.
   * @param {(number|string)} [options.w=null] The write concern.
   * @param {number} [options.wtimeout=null] The write concern timeout.
   * @param {boolean} [options.ordered=true] Execute write operation in ordered or unordered fashion.
   * @param {boolean} [options.bypassDocumentValidation=false] Allow driver to bypass schema validation in MongoDB 3.2 or higher.
   * @param {string|number} [options.w=null] Write concern for the write operation.
   * @param {boolean} [options.j=null] Wait for journal flush on write.
   * @param {number} [options.wtimeout=null] Write concern timeout.
   * @return {Promise} returns Promise
   */
  bulkWrite(operations, options) {
    return this.db.command({
      ns: this.namespace,
      bulkWrite: Object.assign({ops: operations}, options || {})
    });
  }

  /**
   * Creates a cursor for a query that can be used to iterate over results from MongoDB
   * @method
   * @param {object} query The cursor query object.
   * @throws {MongoError}
   * @return {Cursor}
   */
  find(query) {
    return new Cursor(this.db, this, query);
  }

  /**
   * Creates an aggregation cursor for a query that can be used to iterate over results from MongoDB
   * @method
   * @param {array} pipeline The cursor pipeline object.
   * @throws {MongoError}
   * @return {Cursor}
   */
  aggregate(pipeline) {
    return new AggregationCursor({
      aggregate: this.namespace, pipeline: pipeline
    }, this.db, this);
  }
}

module.exports = Collection;
<commit_msg>Added findOne method to the collection object<commit_after>"use strict"

var Promise = require('./util').Promise,
  AggregationCursor = require('./aggregation_cursor'),
  Cursor = require('./cursor');

// Supported options
var findOneOptions = [
  'projection', 'comment', 'hint', 'maxTimeMS', 'sort', 'skip',
];

class Collection {
  constructor(name, db) {
    this.name = name;
    this.db = db;
    this.namespace = db.name + "." + name;
  }

  /**
   * Inserts a single document into MongoDB. If documents passed in do not contain the **_id** field,
   * one will be added to each of the documents missing it by the driver, mutating the document. This behavior
   * can be overridden by setting the **forceServerObjectId** flag.
   *
   * @method
   * @param {object} doc Document to insert.
   * @param {object} [options=null] Optional settings.
   * @param {boolean} [options.bypassDocumentValidation=false] Allow driver to bypass schema validation in MongoDB 3.2 or higher.
   * @param {string|number} [options.w=null] Write concern for the write operation.
   * @param {boolean} [options.j=null] Wait for journal flush on write.
   * @param {number} [options.wtimeout=null] Write concern timeout.
   * @return {Promise} returns Promise
   */
  insertOne(document, options) {
    return this.db.command(Object.assign({
        insertOne: this.namespace,
        doc: document,
      }, options || {})
    );
  }

  /**
   * Inserts an array of documents into MongoDB. If documents passed in do not contain the **_id** field,
   * one will be added to each of the documents missing it by the driver, mutating the document. This behavior
   * can be overridden by setting the **forceServerObjectId** flag.
   *
   * @method
   * @param {object[]} docs Documents to insert.
   * @param {object} [options=null] Optional settings.
   * @param {boolean} [options.ordered=true] Execute write operation in ordered or unordered fashion.
   * @param {boolean} [options.bypassDocumentValidation=false] Allow driver to bypass schema validation in MongoDB 3.2 or higher.
   * @param {string|number} [options.w=null] Write concern for the write operation.
   * @param {boolean} [options.j=null] Wait for journal flush on write.
   * @param {number} [options.wtimeout=null] Write concern timeout.
   * @return {Promise} returns Promise
   */
  insertMany(documents, options) {
    return this.db.command(Object.assign({
        insertMany: this.namespace,
        docs: documents,
      }, options || {})
    );
  }

  /**
   * Update a single document on MongoDB
   * @method
   * @param {object} filter The Filter used to select the document to update
   * @param {object} update The update operations to be applied to the document
   * @param {object} [options=null] Optional settings.
   * @param {boolean} [options.upsert=false] Update operation is an upsert.
   * @param {boolean} [options.bypassDocumentValidation=false] Allow driver to bypass schema validation in MongoDB 3.2 or higher.
   * @param {string|number} [options.w=null] Write concern for the write operation.
   * @param {boolean} [options.j=null] Wait for journal flush on write.
   * @param {number} [options.wtimeout=null] Write concern timeout.
   * @return {Promise} returns Promise
   */
  updateOne(filter, update, options) {
    return this.db.command(Object.assign({
        updateOne: this.namespace,
        q: filter,
        u: update
      }, options || {})
    );
  }

  /**
   * Update multiple documents on MongoDB
   * @method
   * @param {object} filter The Filter used to select the document to update
   * @param {object} update The update operations to be applied to the document
   * @param {object} [options=null] Optional settings.
   * @param {boolean} [options.upsert=false] Update operation is an upsert.
   * @param {boolean} [options.bypassDocumentValidation=false] Allow driver to bypass schema validation in MongoDB 3.2 or higher.
   * @param {string|number} [options.w=null] Write concern for the write operation.
   * @param {boolean} [options.j=null] Wait for journal flush on write.
   * @param {number} [options.wtimeout=null] Write concern timeout.
   * @return {Promise} returns Promise
   */
  updateMany(filter, update, options) {
    return this.db.command(Object.assign({
        updateMany: this.namespace,
        q: filter,
        u: update
      }, options || {})
    );
  }

  /**
   * Replace a document on MongoDB
   * @method
   * @param {object} filter The Filter used to select the document to update
   * @param {object} doc The Document that replaces the matching document
   * @param {object} [options=null] Optional settings.
   * @param {boolean} [options.upsert=false] Update operation is an upsert.
   * @param {boolean} [options.bypassDocumentValidation=false] Allow driver to bypass schema validation in MongoDB 3.2 or higher.
   * @param {string|number} [options.w=null] Write concern for the write operation.
   * @param {boolean} [options.j=null] Wait for journal flush on write.
   * @param {number} [options.wtimeout=null] Write concern timeout.
   * @return {Promise} returns Promise
   */
  replaceOne(filter, doc, options) {
    return this.db.command(Object.assign({
        replaceOne: this.namespace,
        q: filter,
        u: doc
      }, options || {})
    );
  }

  /**
   * Delete a document on MongoDB
   * @method
   * @param {object} filter The Filter used to select the document to remove
   * @param {object} [options=null] Optional settings.
   * @param {string|number} [options.w=null] Write concern for the write operation.
   * @param {boolean} [options.j=null] Wait for journal flush on write.
   * @param {number} [options.wtimeout=null] Write concern timeout.
   * @return {Promise} returns Promise
   */
  deleteOne(filter, options) {
    return this.db.command(Object.assign({
        deleteOne: this.namespace,
        q: filter,
      }, options || {})
    );
  }

  /**
   * Delete multiple documents on MongoDB
   * @method
   * @param {object} filter The Filter used to select the documents to remove
   * @param {object} [options=null] Optional settings.
   * @param {string|number} [options.w=null] Write concern for the write operation.
   * @param {boolean} [options.j=null] Wait for journal flush on write.
   * @param {number} [options.wtimeout=null] Write concern timeout.
   * @return {Promise} returns Promise
   */
  deleteMany(filter, options) {
    return this.db.command(Object.assign({
        deleteMany: this.namespace,
        q: filter,
      }, options || {})
    );
  }

  /**
   * Find a document and delete it in one atomic operation, requires a write lock for the duration of the operation.
   *
   * @method
   * @param {object} filter Document selection filter.
   * @param {object} [options=null] Optional settings.
   * @param {object} [options.projection=null] Limits the fields to return for all matching documents.
   * @param {object} [options.sort=null] Determines which document the operation modifies if the query selects multiple documents.
   * @param {number} [options.maxTimeMS=null] The maximum amount of time to allow the query to run.
   * @param {string|number} [options.w=null] Write concern for the write operation.
   * @param {boolean} [options.j=null] Wait for journal flush on write.
   * @param {number} [options.wtimeout=null] Write concern timeout.
   * @param {boolean} [options.bypassDocumentValidation=false] Allow driver to bypass schema validation in MongoDB 3.2 or higher.
   * @return {Promise} returns Promise
   */
  findOneAndDelete(filter, options) {
    return this.db.command(Object.assign({
        findOneAndDelete: this.namespace,
        q: filter,
      }, options || {})
    );
  }

  /**
   * Find a document and update it in one atomic operation, requires a write lock for the duration of the operation.
   *
   * @method
   * @param {object} filter Document selection filter.
   * @param {object} update Update operations to be performed on the document
   * @param {object} [options=null] Optional settings.
   * @param {object} [options.projection=null] Limits the fields to return for all matching documents.
   * @param {object} [options.sort=null] Determines which document the operation modifies if the query selects multiple documents.
   * @param {number} [options.maxTimeMS=null] The maximum amount of time to allow the query to run.
   * @param {boolean} [options.upsert=false] Upsert the document if it does not exist.
   * @param {boolean} [options.returnOriginal=true] When false, returns the updated document rather than the original. The default is true.
   * @param {string|number} [options.w=null] Write concern for the write operation.
   * @param {boolean} [options.j=null] Wait for journal flush on write.
   * @param {number} [options.wtimeout=null] Write concern timeout.
   * @param {boolean} [options.bypassDocumentValidation=false] Allow driver to bypass schema validation in MongoDB 3.2 or higher.
   * @return {Promise} returns Promise
   */
  findOneAndUpdate(filter, update, options) {
    return this.db.command(Object.assign({
        findOneAndUpdate: this.namespace,
        q: filter,
        u: update
      }, options || {})
    );
  }

  /**
   * Find a document and replace it in one atomic operation, requires a write lock for the duration of the operation.
   *
   * @method
   * @param {object} filter Document selection filter.
   * @param {object} replacement Document replacing the matching document.
   * @param {object} [options=null] Optional settings.
   * @param {object} [options.projection=null] Limits the fields to return for all matching documents.
   * @param {object} [options.sort=null] Determines which document the operation modifies if the query selects multiple documents.
   * @param {number} [options.maxTimeMS=null] The maximum amount of time to allow the query to run.
   * @param {boolean} [options.upsert=false] Upsert the document if it does not exist.
   * @param {boolean} [options.returnOriginal=true] When false, returns the updated document rather than the original. The default is true.
   * @param {string|number} [options.w=null] Write concern for the write operation.
   * @param {boolean} [options.j=null] Wait for journal flush on write.
   * @param {number} [options.wtimeout=null] Write concern timeout.
   * @param {boolean} [options.bypassDocumentValidation=false] Allow driver to bypass schema validation in MongoDB 3.2 or higher.
   * @return {Promise} returns Promise
   */
  findOneAndReplace(filter, replace, options) {
    return this.db.command(Object.assign({
        findOneAndReplace: this.namespace,
        q: filter,
        u: replace
      }, options || {})
    );
  }

  /**
   * Perform a bulkWrite operation without a fluent API
   *
   * Legal operation types are
   *
   *  { insertOne: { document: { a: 1 } } }
   *
   *  { updateOne: { filter: {a:2}, update: {$set: {a:2}}, upsert:true } }
   *
   *  { updateMany: { filter: {a:2}, update: {$set: {a:2}}, upsert:true } }
   *
   *  { deleteOne: { filter: {c:1} } }
   *
   *  { deleteMany: { filter: {c:1} } }
   *
   *  { replaceOne: { filter: {c:3}, replacement: {c:4}, upsert:true}}
   *
   * If documents passed in do not contain the **_id** field,
   * one will be added to each of the documents missing it by the driver, mutating the document. This behavior
   * can be overridden by setting the **forceServerObjectId** flag.
   *
   * @method
   * @param {object[]} operations Bulk operations to perform.
   * @param {object} [options=null] Optional settings.
   * @param {(number|string)} [options.w=null] The write concern.
   * @param {number} [options.wtimeout=null] The write concern timeout.
   * @param {boolean} [options.ordered=true] Execute write operation in ordered or unordered fashion.
   * @param {boolean} [options.bypassDocumentValidation=false] Allow driver to bypass schema validation in MongoDB 3.2 or higher.
   * @param {string|number} [options.w=null] Write concern for the write operation.
   * @param {boolean} [options.j=null] Wait for journal flush on write.
   * @param {number} [options.wtimeout=null] Write concern timeout.
   * @return {Promise} returns Promise
   */
  bulkWrite(operations, options) {
    return this.db.command({
      ns: this.namespace,
      bulkWrite: Object.assign({ops: operations}, options || {})
    });
  }

  /**
   * Creates a cursor for a query that can be used to iterate over results from MongoDB
   * @method
   * @param {object} query The cursor query object.
   * @throws {MongoError}
   * @return {Cursor}
   */
  find(query) {
    return new Cursor(this.db, this, query);
  }

  /**
   * Find the first document in the collection matching the query
   * @method
   * @param {object} query The cursor query object.
   * @param {object} [options=null] Optional settings.
   * @param {object} [options.projection=null] The query projection.
   * @param {string} [options.comment=null] The query comment.
   * @param {object} [options.hint=null] The hint object.
   * @param {number} [options.maxTimeMS=null] The query maxTimeMS.
   * @param {object} [options.sort=null] The query sort order.
   * @param {number} [options.skip=null] The query skip value.
   * @throws {MongoError}
   * @return {Cursor}
   */
  findOne(query, options) {
    options = options || {};
    var cursor = this.find(query);

    for (var i = 0; i < findOneOptions.length; i++) {
      if (options[findOneOptions[i]] != null) {
        cursor[findOneOptions[i]](options[findOneOptions[i]]);
      }
    }

    return cursor.next();
  }

  /**
   * Creates an aggregation cursor for a query that can be used to iterate over results from MongoDB
   * @method
   * @param {array} pipeline The cursor pipeline object.
   * @throws {MongoError}
   * @return {Cursor}
   */
  aggregate(pipeline) {
    return new AggregationCursor({
      aggregate: this.namespace, pipeline: pipeline
    }, this.db, this);
  }
}

module.exports = Collection;
<|endoftext|>


<commit_before>'use strict'

export default function (cepRawValue) {
  return new Promise((resolve, reject) => {
    validateInput(cepRawValue)
      .then(finish)
      .catch(reject)

    function validateInput (cepRawValue) {
      return new Promise(function (resolve, reject) {
        var cepTypeOf = typeof cepRawValue

        if (cepTypeOf === 'number' || cepTypeOf === 'string') {
          return resolve(cepRawValue)
        }

        return reject({
          type: 'type_error',
          message: 'You need to call the constructor with a String or Number.'
        })
      })
    }

    function finish (cepResult) {
      resolve(cepResult)
    }
  })
}
<commit_msg>feat(normalization): adiciona função que remove caracteres especiais<commit_after>'use strict'

export default function (cepRawValue) {
  return new Promise((resolve, reject) => {
    validateInput(cepRawValue)
      .then(removeSpecialCharacters)
      .then(finish)
      .catch(reject)

    function validateInput (cepRawValue) {
      return new Promise(function (resolve, reject) {
        var cepTypeOf = typeof cepRawValue

        if (cepTypeOf === 'number' || cepTypeOf === 'string') {
          return resolve(cepRawValue)
        }

        return reject({
          type: 'type_error',
          message: 'You need to call the constructor with a String or Number.'
        })
      })
    }

    function removeSpecialCharacters (cepRawValue) {
      return new Promise((resolve, reject) => {
        let cepCleanValue = cepRawValue.toString().replace(/[^0-9]+/ig, '')
        resolve(cepCleanValue)
      })
    }

    function finish (cepResult) {
      resolve(cepResult)
    }
  })
}
<|endoftext|>


<commit_before>/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

'use strict';

KylinApp
  .controller('CubesCtrl', function ($scope, $q, $routeParams, $location, $modal, MessageService, CubeDescService, CubeService, JobService, UserService, ProjectService, SweetAlert, loadingRequest, $log, cubeConfig, ProjectModel, ModelService, MetaModel, CubeList,modelsManager,cubesManager,StreamingList,kylinConfig) {

    $scope.cubeConfig = cubeConfig;
    $scope.cubeList = CubeList;

    $scope.modelsManager = modelsManager;
    //$scope.cubesManager = cubesManager;

    $scope.listParams = {
      cubeName: $routeParams.cubeName,
      projectName: $routeParams.projectName
    };
    if ($routeParams.projectName) {
      $scope.projectModel.setSelectedProject($routeParams.projectName);
    }
    CubeList.removeAll();
    $scope.loading = false;
    $scope.action = {};

    $scope.state = {
      filterAttr: 'create_time', filterReverse: true, reverseColumn: 'create_time',
      dimensionFilter: '', measureFilter: ''
    };

    $scope.list = function (offset, limit) {
      var defer = $q.defer();
      if (!$scope.projectModel.projects.length) {
        defer.resolve([]);
        return defer.promise;
      }
      offset = (!!offset) ? offset : 0;
      limit = (!!limit) ? limit : 20;

      var queryParam = {offset: offset, limit: limit};
      if ($scope.listParams.cubeName) {
        queryParam.cubeName = $scope.listParams.cubeName;
      }
      queryParam.projectName = $scope.projectModel.selectedProject;

      $scope.loading = true;

      return CubeList.list(queryParam).then(function (resp) {

        StreamingList.list().then(function(_resp){
          angular.forEach($scope.cubeList.cubes,function(item,index){
            var result = StreamingList.checkCubeExist(item.name);
            if(result.exist == true){
              item.streaming = result.streaming;
              var kfkConfig = StreamingList.getKafkaConfig(result.streaming.name);
              item.kfkConfig = kfkConfig;
            }
          })
        })

        $scope.loading = false;
        defer.resolve(resp);
        return defer.promise;

      },function(resp){
        $scope.loading = false;
        defer.resolve([]);
        SweetAlert.swal('Oops...', resp, 'error');
        return defer.promise;
      });
    };

    $scope.$watch('projectModel.selectedProject', function (newValue, oldValue) {
      if (newValue != oldValue || newValue == null) {
        CubeList.removeAll();
        $scope.reload();
      }

    });
    $scope.reload = function () {
      // trigger reload action in pagination directive
      $scope.action.reload = !$scope.action.reload;
    };

    $scope.loadDetail = function (cube) {
      var defer = $q.defer();
      if (cube.detail) {
        defer.resolve(cube.detail);
      } else {
        CubeDescService.query({cube_name: cube.name}, {}, function (detail) {
          if (detail.length > 0 && detail[0].hasOwnProperty("name")) {
            cube.detail = detail[0];
            cube.model = modelsManager.getModel(cube.detail.model_name);
              defer.resolve(cube.detail);

          } else {
            SweetAlert.swal('Oops...', "No cube detail info loaded.", 'error');
          }
        }, function (e) {
          if (e.data && e.data.exception) {
            var message = e.data.exception;
            var msg = !!(message) ? message : 'Failed to take action.';
            SweetAlert.swal('Oops...', msg, 'error');
          } else {
            SweetAlert.swal('Oops...', "Failed to take action.", 'error');
          }
        });
      }

      return defer.promise;
    };

    $scope.getTotalSize = function (cubes) {
      var size = 0;
      if (!cubes) {
        return 0;
      }
      else {
        for (var i = 0; i < cubes.length; i++) {
          size += cubes[i].size_kb;
        }
        return $scope.dataSize(size * 1024);
      }
    };

//    Cube Action
    $scope.enable = function (cube) {
      SweetAlert.swal({
        title: '',
        text: 'Are you sure to enable the cube? Please note: if cube schema is changed in the disabled period, all segments of the cube will be discarded due to data and schema mismatch.',
        type: '',
        showCancelButton: true,
        confirmButtonColor: '#DD6B55',
//                confirmButtonText: "Yes",
        closeOnConfirm: true
      }, function(isConfirm) {
        if(isConfirm){

          loadingRequest.show();
          CubeService.enable({cubeId: cube.name}, {}, function (result) {

            loadingRequest.hide();
            cube.status = 'READY';
            SweetAlert.swal('Success!', 'Enable job was submitted successfully', 'success');
          },function(e){

            loadingRequest.hide();
            if(e.data&& e.data.exception){
              var message =e.data.exception;
              var msg = !!(message) ? message : 'Failed to take action.';
              SweetAlert.swal('Oops...', msg, 'error');
            }else{
              SweetAlert.swal('Oops...', "Failed to take action.", 'error');
            }
          });
        }
      });
    };

    $scope.purge = function (cube) {
      SweetAlert.swal({
        title: '',
        text: 'Are you sure to purge the cube? ',
        type: '',
        showCancelButton: true,
        confirmButtonColor: '#DD6B55',
        confirmButtonText: "Yes",
        closeOnConfirm: true
      }, function(isConfirm) {
        if(isConfirm){

          loadingRequest.show();
          CubeService.purge({cubeId: cube.name}, {}, function (result) {

            loadingRequest.hide();
//                    CubeList.removeAll();
//                    $scope.reload();
            SweetAlert.swal('Success!', 'Purge job was submitted successfully', 'success');
          },function(e){
            loadingRequest.hide();
            if(e.data&& e.data.exception){
              var message =e.data.exception;
              var msg = !!(message) ? message : 'Failed to take action.';
              SweetAlert.swal('Oops...', msg, 'error');
            }else{
              SweetAlert.swal('Oops...', "Failed to take action.", 'error');
            }
          });
        }
      });
    }

    $scope.disable = function (cube) {

      SweetAlert.swal({
        title: '',
        text: 'Are you sure to disable the cube? ',
        type: '',
        showCancelButton: true,
        confirmButtonColor: '#DD6B55',
        confirmButtonText: "Yes",
        closeOnConfirm: true
      }, function(isConfirm) {
        if(isConfirm){

          loadingRequest.show();
          CubeService.disable({cubeId: cube.name}, {}, function (result) {

            loadingRequest.hide();
            cube.status = 'DISABLED';
            SweetAlert.swal('Success!', 'Disable job was submitted successfully', 'success');
          },function(e){

            loadingRequest.hide();
            if(e.data&& e.data.exception){
              var message =e.data.exception;
              var msg = !!(message) ? message : 'Failed to take action.';
              SweetAlert.swal('Oops...', msg, 'error');
            }else{
              SweetAlert.swal('Oops...', "Failed to take action.", 'error');
            }
          });
        }

      });
    };

    $scope.dropCube = function (cube) {

      SweetAlert.swal({
        title: '',
        text: " Once it's dropped, your cube’s metadata and data will be cleaned up and can’t be restored back. ",
        type: '',
        showCancelButton: true,
        confirmButtonColor: '#DD6B55',
        confirmButtonText: "Yes",
        closeOnConfirm: true
      }, function(isConfirm) {
        if(isConfirm){

          loadingRequest.show();
          CubeService.drop({cubeId: cube.name}, {}, function (result) {
            loadingRequest.hide();
            SweetAlert.swal('Success!', 'Cube drop is done successfully', 'success');
            location.reload();
          },function(e){

            loadingRequest.hide();
            if(e.data&& e.data.exception){
              var message =e.data.exception;
              var msg = !!(message) ? message : 'Failed to take action.';
              SweetAlert.swal('Oops...', msg, 'error');
            }else{
              SweetAlert.swal('Oops...', "Failed to take action.", 'error');
            }
          });
        }

      });
    };

    $scope.startJobSubmit = function (cube) {

      // for streaming cube build tip
      if(cube.streaming){
        $modal.open({
          templateUrl: 'streamingBuild.html',
          controller: streamingBuildCtrl,
          resolve: {
          }
        });
        return;
      }

      $scope.metaModel={
        model:modelsManager.getModelByCube(cube.name)
      }
      if ($scope.metaModel.model.name) {
        if ($scope.metaModel.model.partition_desc.partition_date_column) {
          $modal.open({
            templateUrl: 'jobSubmit.html',
            controller: jobSubmitCtrl,
            resolve: {
              cube: function () {
                return cube;
              },
              metaModel:function(){
                return $scope.metaModel;
              },
              buildType: function () {
                return 'BUILD';
              }
            }
          });
        }
        else {

          SweetAlert.swal({
            title: '',
            text: "Are you sure to start the build ?",
            type: '',
            showCancelButton: true,
            confirmButtonColor: '#DD6B55',
            confirmButtonText: "Yes",
            closeOnConfirm: true
          }, function(isConfirm) {
            if(isConfirm){

              loadingRequest.show();
              CubeService.rebuildCube(
                {
                  cubeId: cube.name
                },
                {
                  buildType: 'BUILD',
                  startTime: 0,
                  endTime: 0
                }, function (job) {

                  loadingRequest.hide();
                  SweetAlert.swal('Success!', 'Rebuild job was submitted successfully', 'success');
                },function(e){

                  loadingRequest.hide();
                  if(e.data&& e.data.exception){
                    var message =e.data.exception;
                    var msg = !!(message) ? message : 'Failed to take action.';
                    SweetAlert.swal('Oops...', msg, 'error');
                  }else{
                    SweetAlert.swal('Oops...', "Failed to take action.", 'error');
                  }
                });
            }

          });
        }
      }
    };

    $scope.startRefresh = function (cube) {
      $scope.metaModel={
        model:modelsManager.getModelByCube(cube.name)
      };
      $modal.open({
        templateUrl: 'jobRefresh.html',
        controller: jobSubmitCtrl,
        resolve: {
          cube: function () {
            return cube;
          },
          metaModel:function(){
            return $scope.metaModel;
          },
          buildType: function () {
            return 'REFRESH';
          }
        }
      });

    };

    $scope.cubeEdit = function (cube) {
      $location.path("cubes/edit/" + cube.name);
    }
    $scope.startMerge = function (cube) {
      $scope.metaModel={
        model:modelsManager.getModelByCube(cube.name)
      };
      $modal.open({
        templateUrl: 'jobMerge.html',
        controller: jobSubmitCtrl,
        resolve: {
          cube: function () {
            return cube;
          },
          metaModel:function(){
            return $scope.metaModel;
          },
          buildType: function () {
            return 'MERGE';
          }
        }
      });
    }
  });

var jobSubmitCtrl = function ($scope, $modalInstance, CubeService, MessageService, $location, cube, metaModel, buildType, SweetAlert, loadingRequest) {
  $scope.cube = cube;
  $scope.metaModel = metaModel;
  $scope.jobBuildRequest = {
    buildType: buildType,
    startTime: 0,
    endTime: 0
  };
  $scope.message = "";

  $scope.rebuild = function (jobsubmit) {

    $scope.message = null;
    $scope.jobBuildRequest.startTime = new Date($scope.jobBuildRequest.startTime).getTime();
    $scope.jobBuildRequest.endTime = new Date($scope.jobBuildRequest.endTime).getTime();

    if ($scope.jobBuildRequest.startTime >= $scope.jobBuildRequest.endTime) {
      $scope.message = "WARNING: End time should be later than the start time.";

      //rollback date setting
      if (jobsubmit) {
        $scope.rebuildRollback();
      }
      return;
    }

    loadingRequest.show();
    CubeService.rebuildCube({cubeId: cube.name}, $scope.jobBuildRequest, function (job) {

      loadingRequest.hide();
      $modalInstance.dismiss('cancel');
      SweetAlert.swal('Success!', 'Rebuild job was submitted successfully', 'success');
    }, function (e) {

      //rollback date setting
      if (jobsubmit) {
        $scope.rebuildRollback();
      }

      loadingRequest.hide();
      if (e.data && e.data.exception) {
        var message = e.data.exception;

        if(message.indexOf("Empty cube segment found")!=-1){
          var _segment = message.substring(message.indexOf(":")+1,message.length-1);
          SweetAlert.swal({
            title:'',
            type:'info',
            text: 'Empty cube segment found'+':'+_segment+', do you want to merge segments forcely ?',
            showCancelButton: true,
            confirmButtonColor: '#DD6B55',
            closeOnConfirm: true
          }, function (isConfirm) {
            if (isConfirm) {
              $scope.jobBuildRequest.forceMergeEmptySegment = true;
              $scope.rebuild(jobsubmit);
            }
          });
          return;
        }

        var msg = !!(message) ? message : 'Failed to take action.';
        SweetAlert.swal('Oops...', msg, 'error');
      } else {
        SweetAlert.swal('Oops...', "Failed to take action.", 'error');
      }
    });
  };

  $scope.rebuildRollback = function () {
    $scope.jobBuildRequest.endTime += new Date().getTimezoneOffset() * 60000;
  }

  // used by cube segment refresh
  $scope.segmentSelected = function (selectedSegment) {
    $scope.jobBuildRequest.startTime = 0;
    $scope.jobBuildRequest.endTime = 0;

    if (selectedSegment.date_range_start) {
      $scope.jobBuildRequest.startTime = selectedSegment.date_range_start;
    }

    if (selectedSegment.date_range_end) {
      $scope.jobBuildRequest.endTime = selectedSegment.date_range_end;
    }
  };

  // used by cube segments merge
  $scope.mergeStartSelected = function (mergeStartSeg) {
    $scope.jobBuildRequest.startTime = 0;

    if (mergeStartSeg.date_range_start) {
      $scope.jobBuildRequest.startTime = mergeStartSeg.date_range_start;
    }
  };

  $scope.mergeEndSelected = function (mergeEndSeg) {
    $scope.jobBuildRequest.endTime = 0;

    if (mergeEndSeg.date_range_end) {
      $scope.jobBuildRequest.endTime = mergeEndSeg.date_range_end;
    }
  };

  $scope.updateDate = function () {
    $scope.jobBuildRequest.endTime = $scope.formatDate($scope.jobBuildRequest.endTime);
  };

  $scope.formatDate = function (timestemp) {
    var dateStart = new Date(timestemp);
    dateStart = (dateStart.getFullYear() + "-" + (dateStart.getMonth() + 1) + "-" + dateStart.getDate());
    //switch selected time to utc timestamp
    return new Date(moment.utc(dateStart, "YYYY-MM-DD").format()).getTime();
  };
  $scope.cancel = function () {
    $modalInstance.dismiss('cancel');
  };
};

var streamingBuildCtrl = function ($scope, $modalInstance,kylinConfig) {
  $scope.kylinConfig = kylinConfig;
  var streamingGuildeUrl = kylinConfig.getProperty("kylin.web.streaming.guide");
  $scope.streamingBuildUrl = streamingGuildeUrl?streamingGuildeUrl:"http://kylin.apache.org/";

  $scope.cancel = function () {
    $modalInstance.dismiss('cancel');
  };
}
<commit_msg>minor, load cube partition date detail when build cube<commit_after>/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

'use strict';

KylinApp
  .controller('CubesCtrl', function ($scope, $q, $routeParams, $location, $modal, MessageService, CubeDescService, CubeService, JobService, UserService, ProjectService, SweetAlert, loadingRequest, $log, cubeConfig, ProjectModel, ModelService, MetaModel, CubeList,modelsManager,cubesManager,StreamingList,kylinConfig) {

    $scope.cubeConfig = cubeConfig;
    $scope.cubeList = CubeList;

    $scope.modelsManager = modelsManager;
    //$scope.cubesManager = cubesManager;

    $scope.listParams = {
      cubeName: $routeParams.cubeName,
      projectName: $routeParams.projectName
    };
    if ($routeParams.projectName) {
      $scope.projectModel.setSelectedProject($routeParams.projectName);
    }
    CubeList.removeAll();
    $scope.loading = false;
    $scope.action = {};

    $scope.state = {
      filterAttr: 'create_time', filterReverse: true, reverseColumn: 'create_time',
      dimensionFilter: '', measureFilter: ''
    };

    $scope.list = function (offset, limit) {
      var defer = $q.defer();
      if (!$scope.projectModel.projects.length) {
        defer.resolve([]);
        return defer.promise;
      }
      offset = (!!offset) ? offset : 0;
      limit = (!!limit) ? limit : 20;

      var queryParam = {offset: offset, limit: limit};
      if ($scope.listParams.cubeName) {
        queryParam.cubeName = $scope.listParams.cubeName;
      }
      queryParam.projectName = $scope.projectModel.selectedProject;

      $scope.loading = true;

      return CubeList.list(queryParam).then(function (resp) {

        StreamingList.list().then(function(_resp){
          angular.forEach($scope.cubeList.cubes,function(item,index){
            var result = StreamingList.checkCubeExist(item.name);
            if(result.exist == true){
              item.streaming = result.streaming;
              var kfkConfig = StreamingList.getKafkaConfig(result.streaming.name);
              item.kfkConfig = kfkConfig;
            }
          })
        })

        $scope.loading = false;
        defer.resolve(resp);
        return defer.promise;

      },function(resp){
        $scope.loading = false;
        defer.resolve([]);
        SweetAlert.swal('Oops...', resp, 'error');
        return defer.promise;
      });
    };

    $scope.$watch('projectModel.selectedProject', function (newValue, oldValue) {
      if (newValue != oldValue || newValue == null) {
        CubeList.removeAll();
        $scope.reload();
      }

    });
    $scope.reload = function () {
      // trigger reload action in pagination directive
      $scope.action.reload = !$scope.action.reload;
    };

    $scope.loadDetail = function (cube) {
      var defer = $q.defer();
      if (cube.detail) {
        defer.resolve(cube.detail);
      } else {
        CubeDescService.query({cube_name: cube.name}, {}, function (detail) {
          if (detail.length > 0 && detail[0].hasOwnProperty("name")) {
            cube.detail = detail[0];
            cube.model = modelsManager.getModel(cube.detail.model_name);
              defer.resolve(cube.detail);

          } else {
            SweetAlert.swal('Oops...', "No cube detail info loaded.", 'error');
          }
        }, function (e) {
          if (e.data && e.data.exception) {
            var message = e.data.exception;
            var msg = !!(message) ? message : 'Failed to take action.';
            SweetAlert.swal('Oops...', msg, 'error');
          } else {
            SweetAlert.swal('Oops...', "Failed to take action.", 'error');
          }
        });
      }

      return defer.promise;
    };

    $scope.getTotalSize = function (cubes) {
      var size = 0;
      if (!cubes) {
        return 0;
      }
      else {
        for (var i = 0; i < cubes.length; i++) {
          size += cubes[i].size_kb;
        }
        return $scope.dataSize(size * 1024);
      }
    };

//    Cube Action
    $scope.enable = function (cube) {
      SweetAlert.swal({
        title: '',
        text: 'Are you sure to enable the cube? Please note: if cube schema is changed in the disabled period, all segments of the cube will be discarded due to data and schema mismatch.',
        type: '',
        showCancelButton: true,
        confirmButtonColor: '#DD6B55',
//                confirmButtonText: "Yes",
        closeOnConfirm: true
      }, function(isConfirm) {
        if(isConfirm){

          loadingRequest.show();
          CubeService.enable({cubeId: cube.name}, {}, function (result) {

            loadingRequest.hide();
            cube.status = 'READY';
            SweetAlert.swal('Success!', 'Enable job was submitted successfully', 'success');
          },function(e){

            loadingRequest.hide();
            if(e.data&& e.data.exception){
              var message =e.data.exception;
              var msg = !!(message) ? message : 'Failed to take action.';
              SweetAlert.swal('Oops...', msg, 'error');
            }else{
              SweetAlert.swal('Oops...', "Failed to take action.", 'error');
            }
          });
        }
      });
    };

    $scope.purge = function (cube) {
      SweetAlert.swal({
        title: '',
        text: 'Are you sure to purge the cube? ',
        type: '',
        showCancelButton: true,
        confirmButtonColor: '#DD6B55',
        confirmButtonText: "Yes",
        closeOnConfirm: true
      }, function(isConfirm) {
        if(isConfirm){

          loadingRequest.show();
          CubeService.purge({cubeId: cube.name}, {}, function (result) {

            loadingRequest.hide();
//                    CubeList.removeAll();
//                    $scope.reload();
            SweetAlert.swal('Success!', 'Purge job was submitted successfully', 'success');
          },function(e){
            loadingRequest.hide();
            if(e.data&& e.data.exception){
              var message =e.data.exception;
              var msg = !!(message) ? message : 'Failed to take action.';
              SweetAlert.swal('Oops...', msg, 'error');
            }else{
              SweetAlert.swal('Oops...', "Failed to take action.", 'error');
            }
          });
        }
      });
    }

    $scope.disable = function (cube) {

      SweetAlert.swal({
        title: '',
        text: 'Are you sure to disable the cube? ',
        type: '',
        showCancelButton: true,
        confirmButtonColor: '#DD6B55',
        confirmButtonText: "Yes",
        closeOnConfirm: true
      }, function(isConfirm) {
        if(isConfirm){

          loadingRequest.show();
          CubeService.disable({cubeId: cube.name}, {}, function (result) {

            loadingRequest.hide();
            cube.status = 'DISABLED';
            SweetAlert.swal('Success!', 'Disable job was submitted successfully', 'success');
          },function(e){

            loadingRequest.hide();
            if(e.data&& e.data.exception){
              var message =e.data.exception;
              var msg = !!(message) ? message : 'Failed to take action.';
              SweetAlert.swal('Oops...', msg, 'error');
            }else{
              SweetAlert.swal('Oops...', "Failed to take action.", 'error');
            }
          });
        }

      });
    };

    $scope.dropCube = function (cube) {

      SweetAlert.swal({
        title: '',
        text: " Once it's dropped, your cube’s metadata and data will be cleaned up and can’t be restored back. ",
        type: '',
        showCancelButton: true,
        confirmButtonColor: '#DD6B55',
        confirmButtonText: "Yes",
        closeOnConfirm: true
      }, function(isConfirm) {
        if(isConfirm){

          loadingRequest.show();
          CubeService.drop({cubeId: cube.name}, {}, function (result) {
            loadingRequest.hide();
            SweetAlert.swal('Success!', 'Cube drop is done successfully', 'success');
            location.reload();
          },function(e){

            loadingRequest.hide();
            if(e.data&& e.data.exception){
              var message =e.data.exception;
              var msg = !!(message) ? message : 'Failed to take action.';
              SweetAlert.swal('Oops...', msg, 'error');
            }else{
              SweetAlert.swal('Oops...', "Failed to take action.", 'error');
            }
          });
        }

      });
    };

    $scope.startJobSubmit = function (cube) {
      $scope.loadDetail(cube);
      // for streaming cube build tip
      if(cube.streaming){
        $modal.open({
          templateUrl: 'streamingBuild.html',
          controller: streamingBuildCtrl,
          resolve: {
          }
        });
        return;
      }

      $scope.metaModel={
        model:modelsManager.getModelByCube(cube.name)
      }
      if ($scope.metaModel.model.name) {
        if ($scope.metaModel.model.partition_desc.partition_date_column) {
          $modal.open({
            templateUrl: 'jobSubmit.html',
            controller: jobSubmitCtrl,
            resolve: {
              cube: function () {
                return cube;
              },
              metaModel:function(){
                return $scope.metaModel;
              },
              buildType: function () {
                return 'BUILD';
              }
            }
          });
        }
        else {

          SweetAlert.swal({
            title: '',
            text: "Are you sure to start the build ?",
            type: '',
            showCancelButton: true,
            confirmButtonColor: '#DD6B55',
            confirmButtonText: "Yes",
            closeOnConfirm: true
          }, function(isConfirm) {
            if(isConfirm){

              loadingRequest.show();
              CubeService.rebuildCube(
                {
                  cubeId: cube.name
                },
                {
                  buildType: 'BUILD',
                  startTime: 0,
                  endTime: 0
                }, function (job) {

                  loadingRequest.hide();
                  SweetAlert.swal('Success!', 'Rebuild job was submitted successfully', 'success');
                },function(e){

                  loadingRequest.hide();
                  if(e.data&& e.data.exception){
                    var message =e.data.exception;
                    var msg = !!(message) ? message : 'Failed to take action.';
                    SweetAlert.swal('Oops...', msg, 'error');
                  }else{
                    SweetAlert.swal('Oops...', "Failed to take action.", 'error');
                  }
                });
            }

          });
        }
      }
    };

    $scope.startRefresh = function (cube) {
      $scope.metaModel={
        model:modelsManager.getModelByCube(cube.name)
      };
      $modal.open({
        templateUrl: 'jobRefresh.html',
        controller: jobSubmitCtrl,
        resolve: {
          cube: function () {
            return cube;
          },
          metaModel:function(){
            return $scope.metaModel;
          },
          buildType: function () {
            return 'REFRESH';
          }
        }
      });

    };

    $scope.cubeEdit = function (cube) {
      $location.path("cubes/edit/" + cube.name);
    }
    $scope.startMerge = function (cube) {
      $scope.metaModel={
        model:modelsManager.getModelByCube(cube.name)
      };
      $modal.open({
        templateUrl: 'jobMerge.html',
        controller: jobSubmitCtrl,
        resolve: {
          cube: function () {
            return cube;
          },
          metaModel:function(){
            return $scope.metaModel;
          },
          buildType: function () {
            return 'MERGE';
          }
        }
      });
    }
  });

var jobSubmitCtrl = function ($scope, $modalInstance, CubeService, MessageService, $location, cube, metaModel, buildType, SweetAlert, loadingRequest) {
  $scope.cube = cube;
  $scope.metaModel = metaModel;
  $scope.jobBuildRequest = {
    buildType: buildType,
    startTime: 0,
    endTime: 0
  };
  $scope.message = "";

  $scope.rebuild = function (jobsubmit) {

    $scope.message = null;
    $scope.jobBuildRequest.startTime = new Date($scope.jobBuildRequest.startTime).getTime();
    $scope.jobBuildRequest.endTime = new Date($scope.jobBuildRequest.endTime).getTime();

    if ($scope.jobBuildRequest.startTime >= $scope.jobBuildRequest.endTime) {
      $scope.message = "WARNING: End time should be later than the start time.";

      //rollback date setting
      if (jobsubmit) {
        $scope.rebuildRollback();
      }
      return;
    }

    loadingRequest.show();
    CubeService.rebuildCube({cubeId: cube.name}, $scope.jobBuildRequest, function (job) {

      loadingRequest.hide();
      $modalInstance.dismiss('cancel');
      SweetAlert.swal('Success!', 'Rebuild job was submitted successfully', 'success');
    }, function (e) {

      //rollback date setting
      if (jobsubmit) {
        $scope.rebuildRollback();
      }

      loadingRequest.hide();
      if (e.data && e.data.exception) {
        var message = e.data.exception;

        if(message.indexOf("Empty cube segment found")!=-1){
          var _segment = message.substring(message.indexOf(":")+1,message.length-1);
          SweetAlert.swal({
            title:'',
            type:'info',
            text: 'Empty cube segment found'+':'+_segment+', do you want to merge segments forcely ?',
            showCancelButton: true,
            confirmButtonColor: '#DD6B55',
            closeOnConfirm: true
          }, function (isConfirm) {
            if (isConfirm) {
              $scope.jobBuildRequest.forceMergeEmptySegment = true;
              $scope.rebuild(jobsubmit);
            }
          });
          return;
        }

        var msg = !!(message) ? message : 'Failed to take action.';
        SweetAlert.swal('Oops...', msg, 'error');
      } else {
        SweetAlert.swal('Oops...', "Failed to take action.", 'error');
      }
    });
  };

  $scope.rebuildRollback = function () {
    $scope.jobBuildRequest.endTime += new Date().getTimezoneOffset() * 60000;
  }

  // used by cube segment refresh
  $scope.segmentSelected = function (selectedSegment) {
    $scope.jobBuildRequest.startTime = 0;
    $scope.jobBuildRequest.endTime = 0;

    if (selectedSegment.date_range_start) {
      $scope.jobBuildRequest.startTime = selectedSegment.date_range_start;
    }

    if (selectedSegment.date_range_end) {
      $scope.jobBuildRequest.endTime = selectedSegment.date_range_end;
    }
  };

  // used by cube segments merge
  $scope.mergeStartSelected = function (mergeStartSeg) {
    $scope.jobBuildRequest.startTime = 0;

    if (mergeStartSeg.date_range_start) {
      $scope.jobBuildRequest.startTime = mergeStartSeg.date_range_start;
    }
  };

  $scope.mergeEndSelected = function (mergeEndSeg) {
    $scope.jobBuildRequest.endTime = 0;

    if (mergeEndSeg.date_range_end) {
      $scope.jobBuildRequest.endTime = mergeEndSeg.date_range_end;
    }
  };

  $scope.updateDate = function () {
    $scope.jobBuildRequest.endTime = $scope.formatDate($scope.jobBuildRequest.endTime);
  };

  $scope.formatDate = function (timestemp) {
    var dateStart = new Date(timestemp);
    dateStart = (dateStart.getFullYear() + "-" + (dateStart.getMonth() + 1) + "-" + dateStart.getDate());
    //switch selected time to utc timestamp
    return new Date(moment.utc(dateStart, "YYYY-MM-DD").format()).getTime();
  };
  $scope.cancel = function () {
    $modalInstance.dismiss('cancel');
  };
};

var streamingBuildCtrl = function ($scope, $modalInstance,kylinConfig) {
  $scope.kylinConfig = kylinConfig;
  var streamingGuildeUrl = kylinConfig.getProperty("kylin.web.streaming.guide");
  $scope.streamingBuildUrl = streamingGuildeUrl?streamingGuildeUrl:"http://kylin.apache.org/";

  $scope.cancel = function () {
    $modalInstance.dismiss('cancel');
  };
}
<|endoftext|>