<commit_before>var locastyle = locastyle || {};

locastyle.dropdown = (function() {
  'use strict';

  var config = {
    area: 'body',
    dropdown: '.ls-dropdown',
    module: '[data-ls-module="dropdown"]',
    button: '[class*="ls-btn"]',
    firstLink: '[data-ls-module="dropdown"] > [class*="ls-btn"]:first-child, .ls-dropdown.ls-user-account > a:first-child',
    nav: '.ls-dropdown-nav'
  };

  function init() {
    unbind();
    bindClickOnTriggers();
    bindClickOutsideTriggers();
    ariaDropdown(config.dropdown);
  }

  function unbind() {
    $(config.firstLink).off("click.ls");
    $(config.area).off("click.ls");
  }

  function bindClickOnTriggers() {
    $(config.firstLink).on("click.ls", function(evt) {
      evt.preventDefault();
      var $target = $($(this).parents(config.module));
      locastyle.dropdown.toggleDropdown($target);
      setPositionVisible($target);
      evt.stopPropagation();
    });
  }

  function bindClickOutsideTriggers() {
    $(config.area).on("click.ls", function(){
      locastyle.dropdown.closeDropdown();
      ariaDropdown(config.dropdown);
    });
  }

  function toggleDropdown($target) {
    if(!$target.find(config.button).first().hasClass('ls-disabled')){
      closeDropdown($target);
      $target.toggleClass("ls-active");
      ariaDropdown($target);
      locastyle.topbarCurtain.hideCurtains();
      eventsHandler($target);
    }
  }

  function eventsHandler(el) {
    if($(el).hasClass("ls-active")) {
      $(el).trigger('dropdown:opened');
    } else {
      $(el).trigger('dropdown:closed');
    }
  }

  function closeDropdown(el) {
    $(config.module).not(el).removeClass("ls-active");
  }

  function setPositionVisible($target){
    var $main = $(config.area);
    if($main.get(0).scrollWidth > $main.width()){
      $($target).addClass('ls-pos-right');
    }
  }

  function ariaDropdown(el) {
    $(config.nav config.button).attr({ 'aria-expanded' : 'false' });
    $(config.nav).attr({ 'aria-hidden' : 'true' });

    $(el).each(function() {
      $(config.nav).find('a').attr({ role : 'option' });
      $(config.button, $(this)).attr({ role : 'combobox' });

      if($(this).hasClass('ls-active')){
        $(config.button, $(this)).attr({ 'aria-expanded' : 'true' });
        $(config.nav, $(this)).attr({ 'aria-hidden' : 'false' });
      } else {
        $(config.button, $(this)).attr({ 'aria-expanded' : 'false' });
        $(config.nav, $(this)).attr({ 'aria-hidden' : 'true' });
      }
    });
  }

  return {
    init: init,
    unbind: unbind,
    toggleDropdown: toggleDropdown,
    closeDropdown: closeDropdown
  };

}());
<commit_msg>fix waiaria dropdown<commit_after>var locastyle = locastyle || {};

locastyle.dropdown = (function() {
  'use strict';

  var config = {
    area: 'body',
    dropdown: '.ls-dropdown',
    module: '[data-ls-module="dropdown"]',
    button: '[class*="ls-btn"]',
    firstLink: '[data-ls-module="dropdown"] > [class*="ls-btn"]:first-child, .ls-dropdown.ls-user-account > a:first-child',
    nav: '.ls-dropdown-nav'
  };

  function init() {
    unbind();
    bindClickOnTriggers();
    bindClickOutsideTriggers();
    ariaDropdown(config.dropdown);
  }

  function unbind() {
    $(config.firstLink).off("click.ls");
    $(config.area).off("click.ls");
  }

  function bindClickOnTriggers() {
    $(config.firstLink).on("click.ls", function(evt) {
      evt.preventDefault();
      var $target = $($(this).parents(config.module));
      locastyle.dropdown.toggleDropdown($target);
      setPositionVisible($target);
      evt.stopPropagation();
    });
  }

  function bindClickOutsideTriggers() {
    $(config.area).on("click.ls", function(){
      locastyle.dropdown.closeDropdown();
      ariaDropdown(config.dropdown);
    });
  }

  function toggleDropdown($target) {
    if(!$target.find(config.button).first().hasClass('ls-disabled')){
      closeDropdown($target);
      $target.toggleClass("ls-active");
      ariaDropdown($target);
      locastyle.topbarCurtain.hideCurtains();
      eventsHandler($target);
    }
  }

  function eventsHandler(el) {
    if($(el).hasClass("ls-active")) {
      $(el).trigger('dropdown:opened');
    } else {
      $(el).trigger('dropdown:closed');
    }
  }

  function closeDropdown(el) {
    $(config.module).not(el).removeClass("ls-active");
  }

  function setPositionVisible($target){
    var $main = $(config.area);
    if($main.get(0).scrollWidth > $main.width()){
      $($target).addClass('ls-pos-right');
    }
  }

  function ariaDropdown(el) {
    $(config.nav).find(config.button).attr({ 'aria-expanded' : 'false' });
    $(config.nav).attr({ 'aria-hidden' : 'true' });

    $(el).each(function() {
      $(config.nav).find('a').attr({ role : 'option' });
      $(config.button, $(this)).attr({ role : 'combobox' });

      if($(this).hasClass('ls-active')){
        $(config.button, $(this)).attr({ 'aria-expanded' : 'true' });
        $(config.nav, $(this)).attr({ 'aria-hidden' : 'false' });
      } else {
        $(config.button, $(this)).attr({ 'aria-expanded' : 'false' });
        $(config.nav, $(this)).attr({ 'aria-hidden' : 'true' });
      }
    });
  }

  return {
    init: init,
    unbind: unbind,
    toggleDropdown: toggleDropdown,
    closeDropdown: closeDropdown
  };

}());
<|endoftext|>


<commit_before>class SightGesture extends Gesture {
  constructor() {
    super();
    this.hoveredCell_ = null;
    this.cellsInSight_ = [];
  }
  startHover(cell) {
    if (cell && cell.role == 'primary') {
      this.hoveredCell_ = cell;
    }
    if (!this.hoveredCell_) return;

    this.cellsInSight_ = this.calculateCellsInSight_(this.hoveredCell_);
    this.cellsInSight_.forEach(cellInSight => {
      cellInSight.showHighlight(ct.overlay, {
        [ck.kind]: ct.overlay.hidden.id,
        [ck.variation]: ct.overlay.hidden.black.id,
      });
    });
  }
  stopHover() {
    this.cellsInSight_.forEach(cellInSight => {
      cellInSight.hideHighlight(ct.overlay);
    });
    this.hoveredCell_ = null;
    this.cellsInSight_ = [];
  }
  startGesture() {}
  continueGesture(cell) {}
  stopGesture() {}

  getColumnCells_(column, columnDiff) {
    const result = [];
    // Initial naive implementation.
    const firstRow = parseInt(state.getProperty(pk.firstRow)) - 1;
    const lastRow = parseInt(state.getProperty(pk.lastRow)) + 1;
    const startRow = columnDiff > 0 ? firstRow : lastRow;
    const endRow = columnDiff > 0 ? lastRow : firstRow;
    for (let row = startRow; row != endRow; row += columnDiff) {
      row = Math.round(row * 2) / 2;
      const cell = state.theMap.getCell(row, column);
      if (cell) result.push(cell);
    }
    return result;
  }

  isOpaque_(cell) {
    return cell.hasLayerContent(ct.walls);
  }

  cleanSectors_(sectors) {
    if (!sectors) return [];
    return sectors.filter(sector => sector.start < sector.end);
  }

  isHiddenByCellsInSameColumn_(cell, originPoint) {
    const seeTop = originPoint.y < cell.offsetTop;
    const seeBottom = originPoint.y > cell.offsetTop + cell.height;
    const isOpaque =
        (row, column) => this.isOpaque_(state.theMap.getCell(row, column));
    if (seeTop && isOpaque(cell.row - 0.5, cell.column)) {
      return true;
    }
    if (seeBottom && isOpaque(cell.row + 0.5, cell.column)) {
      return true;
    }
    return false;
  }

  calculateCellsInSight_(cell) {
    const createOriginPoints = () => [{
      x: cell.offsetLeft + cell.width / 2,
      y: cell.offsetTop + cell.height / 2,
      sectors: [{start: -1, end: 1}],
    }];
    const right =
        this.calculateCellsInQuarterSight_(cell, createOriginPoints(), 0.5);
    const left =
        this.calculateCellsInQuarterSight_(cell, createOriginPoints(), -0.5);
    const uniqueCells = new Set([...right, ...left]);
    return [cell].concat(Array.from(uniqueCells));
  }

  calculateCellsInQuarterSight_(originCell, originPoints, columnDiff) {
    const cellsInSight = [];
    const startColumn = originCell.column + columnDiff;
    const endColumn =
        parseInt(
            state
                .getProperty(columnDiff > 0 ? pk.lastColumn : pk.firstColumn)) +
                columnDiff * 2;
    for (let column = startColumn; column != endColumn; column += columnDiff) {
      column = Math.round(column * 2) / 2;
      const columnCells = this.getColumnCells_(column, columnDiff);
      if (columnCells.length == 0) break;
      const columnLeft = columnCells[0].offsetLeft;
      const columnRight = columnLeft + columnCells[0].width;
      columnCells.forEach(columnCell => {
        const cellIsBeforeOrigin = columnDiff > 0 ?
          columnCell.row <= originCell.row : columnCell.row < originCell.row;
        const cellTop = columnCell.offsetTop;
        const cellBottom = columnCell.offsetTop + columnCell.height;
        const cellStart = columnDiff > 0 ? cellTop : cellBottom;
        const cellEnd = columnDiff > 0 ? cellBottom : cellTop;
        originPoints.forEach(originPoint => {
          const distanceToStart = cellStart - originPoint.y;
          const distanceToEnd = cellEnd - originPoint.y;
          const distanceToLeft = columnLeft - originPoint.x;
          const distanceToRight = columnRight - originPoint.x;
          const cellStartFromScanDirection =
              distanceToStart /
              (cellIsBeforeOrigin ? distanceToLeft : distanceToRight);
          let cellEndFromScanDirection =
              distanceToEnd /
              (cellIsBeforeOrigin ? distanceToLeft : distanceToRight);
          const cellStartFromAntiScanDirection =
              distanceToStart /
              (cellIsBeforeOrigin ? distanceToRight : distanceToLeft);
          let cellEndFromAntiScanDirection =
              distanceToEnd /
              (cellIsBeforeOrigin ? distanceToRight : distanceToLeft);
          if (columnCell.row == originCell.row) {
            const temp = cellEndFromScanDirection;
            cellEndFromScanDirection = cellEndFromAntiScanDirection;
            cellEndFromAntiScanDirection = temp;
          }
          originPoint.sectors.forEach((sector, sectorIndex) => {
            if (!originPoint.nextSectors) {
              originPoint.nextSectors =
                  originPoint.sectors.map(currentSector => ({
                    start: currentSector.start,
                    end: currentSector.end,
                  }));
              originPoint.additionalNextSectorsCount = 0;
            }
            const actualSectorIndex =
                sectorIndex + originPoint.additionalNextSectorsCount;
            let nextSector = originPoint.nextSectors[actualSectorIndex];
            if (sector.start < cellEndFromAntiScanDirection &&
                sector.end > cellStartFromScanDirection) {
              const distanceToFront =
                  columnDiff > 0 ? distanceToLeft : distanceToRight;
              const seenFromTheFront =
                  sector.start <= (distanceToEnd / distanceToFront) &&
                  sector.end >= (distanceToStart / distanceToFront);
              if (seenFromTheFront ||
                  !this.isHiddenByCellsInSameColumn_(columnCell, originPoint)) {
                cellsInSight.push(columnCell);
              }
              const currentCellIsOpaque = this.isOpaque_(columnCell);
              if (currentCellIsOpaque && !sector.prevColCellWasOpaque) {
                nextSector.end =
                    Math.max(nextSector.start, cellStartFromScanDirection);
              } else if (!currentCellIsOpaque && sector.prevColCellWasOpaque) {
                nextSector = {
                  start: Math.min(1, cellStartFromAntiScanDirection),
                  end: sector.end,
                };
                originPoint.nextSectors
                    .splice(actualSectorIndex + 1, 0, nextSector);
                originPoint.additionalNextSectorsCount++;
              }
              sector.prevColCellWasOpaque = currentCellIsOpaque;
            }
          }); // Sectors of origin point loop
        }); // Origin point loop
      }); // Cells in column loop
      originPoints.forEach(originPoint => {
        originPoint.sectors = this.cleanSectors_(originPoint.nextSectors);
        originPoint.nextSectors = null;
        originPoint.additionalNextSectorsCount = 0;
      });
      originPoints =
          originPoints.filter(originPoint => originPoint.sectors.length > 0);
      if (originPoints.length == 0) break;
    } // Column loop
    return cellsInSight;
  }
}
<commit_msg>Sight q1 functional.<commit_after>class SightGesture extends Gesture {
  constructor() {
    super();
    this.hoveredCell_ = null;
    this.cellsInSight_ = [];
  }
  startHover(cell) {
    if (cell && cell.role == 'primary') {
      this.hoveredCell_ = cell;
    }
    if (!this.hoveredCell_) return;

    this.cellsInSight_ = this.calculateCellsInSight_(this.hoveredCell_);
    this.cellsInSight_.forEach(cellInSight => {
      cellInSight.showHighlight(ct.overlay, {
        [ck.kind]: ct.overlay.hidden.id,
        [ck.variation]: ct.overlay.hidden.black.id,
      });
    });
  }
  stopHover() {
    this.cellsInSight_.forEach(cellInSight => {
      cellInSight.hideHighlight(ct.overlay);
    });
    this.hoveredCell_ = null;
    this.cellsInSight_ = [];
  }
  startGesture() {}
  continueGesture(cell) {}
  stopGesture() {}

  getColumnCells_(column, columnDiff) {
    const result = [];
    // Naive implementation.
    const firstRow = parseInt(state.getProperty(pk.firstRow)) - 1;
    const lastRow = parseInt(state.getProperty(pk.lastRow)) + 1;
    const startRow = columnDiff > 0 ? firstRow : lastRow;
    const endRow = columnDiff > 0 ? lastRow : firstRow;
    for (let row = startRow; row != endRow; row += columnDiff) {
      row = Math.round(row * 2) / 2;
      const cell = state.theMap.getCell(row, column);
      if (cell) result.push(cell);
    }
    return result;
  }

  getRowCells_(row, rowDiff) {
    const result = [];
    // Naive implementation.
    const firstColumn = parseInt(state.getProperty(pk.firstColumn)) - 1;
    const lastColumn = parseInt(state.getProperty(pk.lastColumn)) + 1;
    const startColumn = rowDiff > 0 ? firstColumn : lastColumn;
    const endColumn = rowDiff > 0 ? lastColumn : firstColumn;
    for (let column = startColumn; column != endColumn; column += rowDiff) {
      column = Math.round(column * 2) / 2;
      const cell = state.theMap.getCell(row, column);
      if (cell) result.push(cell);
    }
    return result;
  }

  isOpaque_(cell) {
    return cell && cell.hasLayerContent(ct.walls);
  }

  cleanSectors_(sectors) {
    if (!sectors) return [];
    return sectors.filter(sector => sector.start < sector.end);
  }

  isHiddenByCellsInSameColumn_(cell, originPoint) {
    const seeTop = originPoint.y < cell.offsetTop;
    const seeBottom = originPoint.y > cell.offsetTop + cell.height;
    const isOpaque =
        (row, column) => this.isOpaque_(state.theMap.getCell(row, column));
    if (seeTop && isOpaque(cell.row - 0.5, cell.column)) {
      return true;
    }
    if (seeBottom && isOpaque(cell.row + 0.5, cell.column)) {
      return true;
    }
    return false;
  }

  isHiddenByCellsInSameRow_(cell, originPoint) {
    const seeLeft = originPoint.x < cell.offsetLeft;
    const seeRight = originPoint.x > cell.offsetLeft + cell.width;
    const isOpaque =
        (row, column) => this.isOpaque_(state.theMap.getCell(row, column));
    if (seeLeft && isOpaque(cell.row, cell.column - 0.5)) {
      return true;
    }
    if (seeRight && isOpaque(cell.row, cell.column + 0.5)) {
      return true;
    }
    return false;
  }

  calculateCellsInSight_(cell) {
    const createOriginPoints = () => [{
      x: cell.offsetLeft + cell.width / 2,
      y: cell.offsetTop + cell.height / 2,
      sectors: [{start: -1, end: 1}],
    }];
    const right =
        this.calculateCellsInSightByColumn_(cell, createOriginPoints(), 0.5);
    const left =
        this.calculateCellsInSightByColumn_(cell, createOriginPoints(), -0.5);
    const bottom =
        this.calculateCellsInSightByRow_(cell, createOriginPoints(), 0.5);
    const uniqueCells = new Set([...right, ...left, ...bottom]);
    return [cell].concat(Array.from(uniqueCells));
  }

  calculateCellsInSightByColumn_(originCell, originPoints, columnDiff) {
    const cellsInSight = [];
    const startColumn = originCell.column + columnDiff;
    const endColumn =
        parseInt(
            state
                .getProperty(columnDiff > 0 ? pk.lastColumn : pk.firstColumn)) +
                columnDiff * 2;
    for (let column = startColumn; column != endColumn; column += columnDiff) {
      column = Math.round(column * 2) / 2;
      const columnCells = this.getColumnCells_(column, columnDiff);
      if (columnCells.length == 0) break;
      const columnLeft = columnCells[0].offsetLeft;
      const columnRight = columnLeft + columnCells[0].width;
      columnCells.forEach(columnCell => {
        const cellIsBeforeOrigin = columnDiff > 0 ?
          columnCell.row <= originCell.row : columnCell.row < originCell.row;
        const cellTop = columnCell.offsetTop;
        const cellBottom = columnCell.offsetTop + columnCell.height;
        const cellStart = columnDiff > 0 ? cellTop : cellBottom;
        const cellEnd = columnDiff > 0 ? cellBottom : cellTop;
        originPoints.forEach(originPoint => {
          const distanceToStart = cellStart - originPoint.y;
          const distanceToEnd = cellEnd - originPoint.y;
          const distanceToLeft = columnLeft - originPoint.x;
          const distanceToRight = columnRight - originPoint.x;
          const cellStartFromScanDirection =
              distanceToStart /
              (cellIsBeforeOrigin ? distanceToLeft : distanceToRight);
          let cellEndFromScanDirection =
              distanceToEnd /
              (cellIsBeforeOrigin ? distanceToLeft : distanceToRight);
          const cellStartFromAntiScanDirection =
              distanceToStart /
              (cellIsBeforeOrigin ? distanceToRight : distanceToLeft);
          let cellEndFromAntiScanDirection =
              distanceToEnd /
              (cellIsBeforeOrigin ? distanceToRight : distanceToLeft);
          if (columnCell.row == originCell.row) {
            const temp = cellEndFromScanDirection;
            cellEndFromScanDirection = cellEndFromAntiScanDirection;
            cellEndFromAntiScanDirection = temp;
          }
          originPoint.sectors.forEach((sector, sectorIndex) => {
            if (!originPoint.nextSectors) {
              originPoint.nextSectors =
                  originPoint.sectors.map(currentSector => ({
                    start: currentSector.start,
                    end: currentSector.end,
                  }));
              originPoint.additionalNextSectorsCount = 0;
            }
            const actualSectorIndex =
                sectorIndex + originPoint.additionalNextSectorsCount;
            let nextSector = originPoint.nextSectors[actualSectorIndex];
            if (sector.start < cellEndFromAntiScanDirection &&
                sector.end > cellStartFromScanDirection) {
              const distanceToFront =
                  columnDiff > 0 ? distanceToLeft : distanceToRight;
              const seenFromTheFront =
                  sector.start <= (distanceToEnd / distanceToFront) &&
                  sector.end >= (distanceToStart / distanceToFront);
              if (seenFromTheFront ||
                  !this.isHiddenByCellsInSameColumn_(columnCell, originPoint)) {
                cellsInSight.push(columnCell);
              }
              const currentCellIsOpaque = this.isOpaque_(columnCell);
              if (currentCellIsOpaque && !sector.prevColCellWasOpaque) {
                nextSector.end =
                    Math.max(nextSector.start, cellStartFromScanDirection);
              } else if (!currentCellIsOpaque && sector.prevColCellWasOpaque) {
                nextSector = {
                  start: Math.min(1, cellStartFromAntiScanDirection),
                  end: sector.end,
                };
                originPoint.nextSectors
                    .splice(actualSectorIndex + 1, 0, nextSector);
                originPoint.additionalNextSectorsCount++;
              }
              sector.prevColCellWasOpaque = currentCellIsOpaque;
            }
          }); // Sectors of origin point loop
        }); // Origin point loop
      }); // Cells in column loop
      originPoints.forEach(originPoint => {
        originPoint.sectors = this.cleanSectors_(originPoint.nextSectors);
        originPoint.nextSectors = null;
        originPoint.additionalNextSectorsCount = 0;
      });
      originPoints =
          originPoints.filter(originPoint => originPoint.sectors.length > 0);
      if (originPoints.length == 0) break;
    } // Column loop
    return cellsInSight;
  }

  calculateCellsInSightByRow_(originCell, originPoints, rowDiff) {
    const cellsInSight = [];
    const startRow = originCell.row + rowDiff;
    const endRow =
        parseInt(
            state
                .getProperty(rowDiff > 0 ? pk.lastRow : pk.firstRow)) +
                rowDiff * 2;
    for (let row = startRow; row != endRow; row += rowDiff) {
      row = Math.round(row * 2) / 2;
      const rowCells = this.getRowCells_(row, rowDiff);
      if (rowCells.length == 0) break;
      const rowTop = rowCells[0].offsetTop;
      const rowBottom = rowTop + rowCells[0].height;
      rowCells.forEach(rowCell => {
        const cellIsBeforeOrigin = rowDiff > 0 ?
          rowCell.column <= originCell.column :
          rowCell.column < originCell.column;
        const cellLeft = rowCell.offsetLeft;
        const cellRight = rowCell.offsetLeft + rowCell.width;
        const cellStart = rowDiff > 0 ? cellLeft : cellRight;
        const cellEnd = rowDiff > 0 ? cellRight : cellLeft;
        originPoints.forEach(originPoint => {
          const distanceToStart = cellStart - originPoint.x;
          const distanceToEnd = cellEnd - originPoint.x;
          const distanceToTop = rowTop - originPoint.y;
          const distanceToBottom = rowBottom - originPoint.y;
          const cellStartFromScanDirection =
              distanceToStart /
              (cellIsBeforeOrigin ? distanceToTop : distanceToBottom);
          let cellEndFromScanDirection =
              distanceToEnd /
              (cellIsBeforeOrigin ? distanceToTop : distanceToBottom);
          const cellStartFromAntiScanDirection =
              distanceToStart /
              (cellIsBeforeOrigin ? distanceToBottom : distanceToTop);
          let cellEndFromAntiScanDirection =
              distanceToEnd /
              (cellIsBeforeOrigin ? distanceToBottom : distanceToTop);
          if (rowCell.column == rowCell.column) {
            const temp = cellEndFromScanDirection;
            cellEndFromScanDirection = cellEndFromAntiScanDirection;
            cellEndFromAntiScanDirection = temp;
          }
          originPoint.sectors.forEach((sector, sectorIndex) => {
            if (!originPoint.nextSectors) {
              originPoint.nextSectors =
                  originPoint.sectors.map(currentSector => ({
                    start: currentSector.start,
                    end: currentSector.end,
                  }));
              originPoint.additionalNextSectorsCount = 0;
            }
            const actualSectorIndex =
                sectorIndex + originPoint.additionalNextSectorsCount;
            let nextSector = originPoint.nextSectors[actualSectorIndex];
            if (sector.start < cellEndFromAntiScanDirection &&
                sector.end > cellStartFromScanDirection) {
              const distanceToFront =
                  rowDiff > 0 ? distanceToTop : distanceToBottom;
              const seenFromTheFront =
                  sector.start <= (distanceToEnd / distanceToFront) &&
                  sector.end >= (distanceToStart / distanceToFront);
              if (seenFromTheFront ||
                  !this.isHiddenByCellsInSameRow_(rowCell, originPoint)) {
                cellsInSight.push(rowCell);
              }
              const currentCellIsOpaque = this.isOpaque_(rowCell);
              if (currentCellIsOpaque && !sector.prevRowCellWasOpaque) {
                nextSector.end =
                    Math.max(nextSector.start, cellStartFromScanDirection);
              } else if (!currentCellIsOpaque && sector.prevRowCellWasOpaque) {
                nextSector = {
                  start: Math.min(1, cellStartFromAntiScanDirection),
                  end: sector.end,
                };
                originPoint.nextSectors
                    .splice(actualSectorIndex + 1, 0, nextSector);
                originPoint.additionalNextSectorsCount++;
              }
              sector.prevRowCellWasOpaque = currentCellIsOpaque;
            }
          }); // Sectors of origin point loop
        }); // Origin point loop
      }); // Cells in row loop
      originPoints.forEach(originPoint => {
        originPoint.sectors = this.cleanSectors_(originPoint.nextSectors);
        originPoint.nextSectors = null;
        originPoint.additionalNextSectorsCount = 0;
      });
      originPoints =
          originPoints.filter(originPoint => originPoint.sectors.length > 0);
      if (originPoints.length == 0) break;
    } // row loop
    return cellsInSight;
  }
}
<|endoftext|>


<commit_before>// Avoid `console` errors in browsers that lack a console.
if (!(window.console && console.log)) {
    (function() {
        var noop = function() {};
        var methods = ['assert', 'clear', 'count', 'debug', 'dir', 'dirxml', 'error', 'exception', 'group', 'groupCollapsed', 'groupEnd', 'info', 'log', 'markTimeline', 'profile', 'profileEnd', 'markTimeline', 'table', 'time', 'timeEnd', 'timeStamp', 'trace', 'warn'];
        var length = methods.length;
        var console = window.console = {};
        while (length--) {
            console[methods[length]] = noop;
        }
    }());
}

//
//
// MAP PICKER
//
//

/**
 *
 * A JQUERY GOOGLE MAPS LATITUDE AND LONGITUDE LOCATION PICKER
 * version 1.1
 *
 * Supports multiple maps. Works on touchscreen. Easy to customize markup and CSS.
 *
 * To see a live demo, go to:
 * http://wimagguc.hu/projects/jquery-latitude-longitude-picker-gmaps/
 *
 * by Richard Dancsi
 * http://wimagguc.hu/
 *
 */

var GMapsLatLonPicker = (function() {

  var _self = this;

  ///////////////////////////////////////////////////////////////////////////////////////////////
  // PARAMETERS (MODIFY THIS PART) //////////////////////////////////////////////////////////////
  _self.params = {
    defLat : 0,
    defLng : 0,
    defZoom : 1,
    queryLocationNameWhenLatLngChanges: true,
    mapOptions : {
      mapTypeId: google.maps.MapTypeId.ROADMAP,
      mapTypeControl: false,
      disableDoubleClickZoom: true,
      zoomControlOptions: true,
      streetViewControl: false
    },
    strings : {
      markerText : "Drag this Marker",
      error_empty_field : "Couldn't find coordinates for this place",
      error_no_results : "Couldn't find coordinates for this place"
    }
  };

  ///////////////////////////////////////////////////////////////////////////////////////////////
  // VARIABLES USED BY THE FUNCTION (DON'T MODIFY THIS PART) ////////////////////////////////////
  _self.vars = {
    ID : null,
    LATLNG : null,
    map : null,
    marker : null,
    geocoder : null
  };

  ///////////////////////////////////////////////////////////////////////////////////////////////
  // PRIVATE FUNCTIONS FOR MANIPULATING DATA ////////////////////////////////////////////////////
    var setPosition = function(position) {
      _self.vars.marker.setPosition(position);
    _self.vars.map.panTo(position);

    $(_self.vars.cssID + ".gllpZoom").val( _self.vars.map.getZoom() );
    $(_self.vars.cssID + ".gllpLongitude").val( position.lng() );
    $(_self.vars.cssID + ".gllpLatitude").val( position.lat() );

    $(_self.vars.cssID).trigger("location_changed", $(_self.vars.cssID));

    if (_self.params.queryLocationNameWhenLatLngChanges) {
      getLocationName(position);
    }
    };

    // for reverse geocoding
    var getLocationName = function(position) {
    var latlng = new google.maps.LatLng(position.lat(), position.lng());
      _self.vars.geocoder.geocode({'latLng': latlng}, function(results, status) {
        if (status == google.maps.GeocoderStatus.OK && results[1]) {
              $(_self.vars.cssID + ".gllpLocationName").val(results[1].formatted_address);
            } else {
              $(_self.vars.cssID + ".gllpLocationName").val("");
            }
    });
    };

  // search function
    var performSearch = function(string, silent) {
    if (string == "") {
      if (!silent) {
        displayError( _self.params.strings.error_empty_field );
      }
      return;
    }
    _self.vars.geocoder.geocode(
      {"address": string},
      function(results, status) {
        if (status == google.maps.GeocoderStatus.OK) {
          $(_self.vars.cssID + ".gllpZoom").val(13);
          _self.vars.map.setZoom( parseInt($(_self.vars.cssID + ".gllpZoom").val()) );
          setPosition( results[0].geometry.location );
        } else {
          if (!silent) {
            displayError( _self.params.strings.error_no_results );
          }
        }
      }
    );
    };

    // error function
    var displayError = function(message) {
      alert(message);
    };

  ///////////////////////////////////////////////////////////////////////////////////////////////
  // PUBLIC FUNCTIONS  //////////////////////////////////////////////////////////////////////////
  var publicfunc = {

    // INITIALIZE MAP ON DIV //////////////////////////////////////////////////////////////////
    init : function(object) {

      if ( !$(object).attr("id") ) {
        if ( $(object).attr("name") ) {
          $(object).attr("id", $(object).attr("name") );
        } else {
          $(object).attr("id", "_MAP_" + Math.ceil(Math.random() * 10000) );
        }
      }

      _self.vars.ID = $(object).attr("id");
      _self.vars.cssID = "#" + _self.vars.ID + " ";

      _self.params.defLat  = $(_self.vars.cssID + ".gllpLatitude").val()  ? $(_self.vars.cssID + ".gllpLatitude").val()        : _self.params.defLat;
      _self.params.defLng  = $(_self.vars.cssID + ".gllpLongitude").val() ? $(_self.vars.cssID + ".gllpLongitude").val()       : _self.params.defLng;
      _self.params.defZoom = $(_self.vars.cssID + ".gllpZoom").val()      ? parseInt($(_self.vars.cssID + ".gllpZoom").val())  : _self.params.defZoom;

      _self.vars.LATLNG = new google.maps.LatLng(_self.params.defLat, _self.params.defLng);

      _self.vars.MAPOPTIONS        = _self.params.mapOptions;
      _self.vars.MAPOPTIONS.zoom   = _self.params.defZoom;
      _self.vars.MAPOPTIONS.center = _self.vars.LATLNG;

      _self.vars.map = new google.maps.Map($(_self.vars.cssID + ".gllpMap").get(0), _self.vars.MAPOPTIONS);
      _self.vars.geocoder = new google.maps.Geocoder();

      _self.vars.marker = new google.maps.Marker({
        position: _self.vars.LATLNG,
        map: _self.vars.map,
        title: _self.params.strings.markerText,
        draggable: true
      });

      // Set position on doubleclick
      google.maps.event.addListener(_self.vars.map, 'dblclick', function(event) {
          setPosition(event.latLng);
        });

      // Set position on marker move
        google.maps.event.addListener(_self.vars.marker, 'dragend', function(event) {
          setPosition(_self.vars.marker.position);
        });

      // Set zoom feld's value when user changes zoom on the map
      google.maps.event.addListener(_self.vars.map, 'zoom_changed', function(event) {
        $(_self.vars.cssID + ".gllpZoom").val( _self.vars.map.getZoom() );
        $(_self.vars.cssID).trigger("location_changed", $(_self.vars.cssID));
        });

      // Update location and zoom values based on input field's value
      $(_self.vars.cssID + ".gllpUpdateButton").bind("click", function() {
        var lat = $(_self.vars.cssID + ".gllpLatitude").val();
        var lng = $(_self.vars.cssID + ".gllpLongitude").val();
        var latlng = new google.maps.LatLng(lat, lng);
        _self.vars.map.setZoom( parseInt( $(_self.vars.cssID + ".gllpZoom").val() ) );
        setPosition(latlng);
      });

      // Search function by search button
      $(_self.vars.cssID + ".gllpSearchButton").bind("click", function() {
        performSearch( $(_self.vars.cssID + ".gllpSearchField").val(), false );
      });

      // Search function by gllp_perform_search listener
      $(document).bind("gllp_perform_search", function(event, object) {
        performSearch( $(object).attr('string'), true );
      });
    },

    custom_redraw : function() {
      var lat = $(_self.vars.cssID + ".gllpLatitude").val();
      var lng = $(_self.vars.cssID + ".gllpLongitude").val();
      var latlng = new google.maps.LatLng(lat, lng);
      _self.vars.map.setZoom( parseInt( $(_self.vars.cssID + ".gllpZoom").val() ) );
      setPosition(latlng);
    }

  }

  return publicfunc;
});
<commit_msg>Fixed a search bug<commit_after>// Avoid `console` errors in browsers that lack a console.
if (!(window.console && console.log)) {
    (function() {
        var noop = function() {};
        var methods = ['assert', 'clear', 'count', 'debug', 'dir', 'dirxml', 'error', 'exception', 'group', 'groupCollapsed', 'groupEnd', 'info', 'log', 'markTimeline', 'profile', 'profileEnd', 'markTimeline', 'table', 'time', 'timeEnd', 'timeStamp', 'trace', 'warn'];
        var length = methods.length;
        var console = window.console = {};
        while (length--) {
            console[methods[length]] = noop;
        }
    }());
}

//
//
// MAP PICKER
//
//

/**
 *
 * A JQUERY GOOGLE MAPS LATITUDE AND LONGITUDE LOCATION PICKER
 * version 1.1
 *
 * Supports multiple maps. Works on touchscreen. Easy to customize markup and CSS.
 *
 * To see a live demo, go to:
 * http://wimagguc.hu/projects/jquery-latitude-longitude-picker-gmaps/
 *
 * by Richard Dancsi
 * http://wimagguc.hu/
 *
 */

var GMapsLatLonPicker = (function() {

  var _self = this;

  ///////////////////////////////////////////////////////////////////////////////////////////////
  // PARAMETERS (MODIFY THIS PART) //////////////////////////////////////////////////////////////
  _self.params = {
    defLat : 0,
    defLng : 0,
    defZoom : 1,
    queryLocationNameWhenLatLngChanges: true,
    mapOptions : {
      mapTypeId: google.maps.MapTypeId.ROADMAP,
      mapTypeControl: false,
      disableDoubleClickZoom: true,
      zoomControlOptions: true,
      streetViewControl: false
    },
    strings : {
      markerText : "Drag this Marker",
      error_empty_field : "Couldn't find coordinates for this place",
      error_no_results : "Couldn't find coordinates for this place"
    }
  };

  ///////////////////////////////////////////////////////////////////////////////////////////////
  // VARIABLES USED BY THE FUNCTION (DON'T MODIFY THIS PART) ////////////////////////////////////
  _self.vars = {
    ID : null,
    LATLNG : null,
    map : null,
    marker : null,
    geocoder : null
  };

  ///////////////////////////////////////////////////////////////////////////////////////////////
  // PRIVATE FUNCTIONS FOR MANIPULATING DATA ////////////////////////////////////////////////////
    var setPosition = function(position) {
      _self.vars.marker.setPosition(position);
    _self.vars.map.panTo(position);

    $(_self.vars.cssID + ".gllpZoom").val( _self.vars.map.getZoom() );
    $(_self.vars.cssID + ".gllpLongitude").val( position.lng() );
    $(_self.vars.cssID + ".gllpLatitude").val( position.lat() );

    $(_self.vars.cssID).trigger("location_changed", $(_self.vars.cssID));

    if (_self.params.queryLocationNameWhenLatLngChanges) {
      getLocationName(position);
    }
    };

    // for reverse geocoding
    var getLocationName = function(position) {
    var latlng = new google.maps.LatLng(position.lat(), position.lng());
      _self.vars.geocoder.geocode({'latLng': latlng}, function(results, status) {
        if (status == google.maps.GeocoderStatus.OK && results[1]) {
              $(_self.vars.cssID + ".gllpLocationName").val(results[1].formatted_address);
            } else {
              $(_self.vars.cssID + ".gllpLocationName").val("");
            }
    });
    };

  // search function
    var performSearch = function(string, silent) {
    if (string == "") {
      if (!silent) {
        displayError( _self.params.strings.error_empty_field );
      }
      return;
    }
    _self.vars.geocoder.geocode(
      {"address": string},
      function(results, status) {
        if (status == google.maps.GeocoderStatus.OK) {
          $(_self.vars.cssID + ".gllpZoom").val(13);
          _self.vars.map.setZoom( parseInt($(_self.vars.cssID + ".gllpZoom").val()) );
          setPosition( results[0].geometry.location );
        } else {
          if (!silent) {
            displayError( _self.params.strings.error_no_results );
          }
        }
      }
    );
    };

    // error function
    var displayError = function(message) {
      alert(message);
    };

  ///////////////////////////////////////////////////////////////////////////////////////////////
  // PUBLIC FUNCTIONS  //////////////////////////////////////////////////////////////////////////
  var publicfunc = {

    // INITIALIZE MAP ON DIV //////////////////////////////////////////////////////////////////
    init : function(object) {

      if ( !$(object).attr("id") ) {
        if ( $(object).attr("name") ) {
          $(object).attr("id", $(object).attr("name") );
        } else {
          $(object).attr("id", "_MAP_" + Math.ceil(Math.random() * 10000) );
        }
      }

      _self.vars.ID = $(object).attr("id");
      _self.vars.cssID = "#" + _self.vars.ID + " ";

      _self.params.defLat  = $(_self.vars.cssID + ".gllpLatitude").val()  ? $(_self.vars.cssID + ".gllpLatitude").val()        : _self.params.defLat;
      _self.params.defLng  = $(_self.vars.cssID + ".gllpLongitude").val() ? $(_self.vars.cssID + ".gllpLongitude").val()       : _self.params.defLng;
      _self.params.defZoom = $(_self.vars.cssID + ".gllpZoom").val()      ? parseInt($(_self.vars.cssID + ".gllpZoom").val())  : _self.params.defZoom;

      _self.vars.LATLNG = new google.maps.LatLng(_self.params.defLat, _self.params.defLng);

      _self.vars.MAPOPTIONS        = _self.params.mapOptions;
      _self.vars.MAPOPTIONS.zoom   = _self.params.defZoom;
      _self.vars.MAPOPTIONS.center = _self.vars.LATLNG;

      _self.vars.map = new google.maps.Map($(_self.vars.cssID + ".gllpMap").get(0), _self.vars.MAPOPTIONS);
      _self.vars.geocoder = new google.maps.Geocoder();

      _self.vars.marker = new google.maps.Marker({
        position: _self.vars.LATLNG,
        map: _self.vars.map,
        title: _self.params.strings.markerText,
        draggable: true
      });

      // Set position on doubleclick
      google.maps.event.addListener(_self.vars.map, 'dblclick', function(event) {
          setPosition(event.latLng);
        });

      // Set position on marker move
        google.maps.event.addListener(_self.vars.marker, 'dragend', function(event) {
          setPosition(_self.vars.marker.position);
        });

      // Set zoom feld's value when user changes zoom on the map
      google.maps.event.addListener(_self.vars.map, 'zoom_changed', function(event) {
        $(_self.vars.cssID + ".gllpZoom").val( _self.vars.map.getZoom() );
        $(_self.vars.cssID).trigger("location_changed", $(_self.vars.cssID));
        });

      // Update location and zoom values based on input field's value
      $(_self.vars.cssID + ".gllpUpdateButton").bind("click", function() {
        var lat = $(_self.vars.cssID + ".gllpLatitude").val();
        var lng = $(_self.vars.cssID + ".gllpLongitude").val();
        var latlng = new google.maps.LatLng(lat, lng);
        _self.vars.map.setZoom( parseInt( $(_self.vars.cssID + ".gllpZoom").val() ) );
        setPosition(latlng);
      });

      // Search function by search button
      $(_self.vars.cssID + ".gllpSearchButton").bind("click", function() {
        performSearch( $(_self.vars.cssID + ".gllpSearchField").val(), false );
      });

      // Search function by gllp_perform_search listener
      $(document).bind("gllp_perform_search", function(event, object) {
        performSearch( $(object).attr('string'), true );
      });
    },

    custom_redraw : function() {
      var lat = $(_self.vars.cssID + ".gllpLatitude").val();
      var lng = $(_self.vars.cssID + ".gllpLongitude").val();
      var latlng = new google.maps.LatLng(lat, lng);
      _self.vars.map.setZoom( parseInt( $(_self.vars.cssID + ".gllpZoom").val() ) );
      setPosition(latlng);
    },

    performSearch : performSearch

  }

  return publicfunc;
});
<|endoftext|>


<commit_before>var jsonUtils = require('../utils/json');
var nodeURL = require("url");
var repoClients;

function contributorStatistics (request, response)    {

    var dataOut = {},
        responseCount,
        urlQuery = nodeURL.parse(request.url, true).query;

    if(nodeURL.parse(request.url).query !== null && urlQuery.repo != "all")   {

        if (repoClients[urlQuery.repo]) {

            dataOut[urlQuery.repo] = [];

            repoClients[urlQuery.repo].github.repos.getContributors({
                "user": urlQuery.repo.split("/").shift(),
                "repo": urlQuery.repo.split("/").pop(),
                "anon": false
            }, function(errors, contribs){
                if (errors == null) {

                    dataOut[urlQuery.repo] = contribs.map(function(nextContrib){

                        return {
                            "login": nextContrib.login,
                            "contributions": nextContrib.contributions
                        };

                    });

                    jsonUtils.render(dataOut, response, urlQuery.callback);

                }
            });

        } else {

            jsonUtils.renderErrors([new Error("Not monitoring this repository!")], response, urlQuery.callback);

        }

    } else {

        responseCount = 0;

        Object.keys(repoClients).forEach(function (nextRepo) {

            dataOut[nextRepo] = [];

            repoClients[nextRepo].github.repos.getContributors({
                "user": repoClients[nextRepo].toString().split("/").shift(),
                "repo": repoClients[nextRepo].toString().split("/").pop(),
                "anon": false
            }, function(errors, contribs){

                if (errors == null) {

                    dataOut[nextRepo] = contribs.map(function(nextContrib){

                        return {
                            "login": nextContrib.login,
                            "contributions": nextContrib.contributions
                        };

                    });

                    responseCount++;

                    if (responseCount >= Object.keys(repoClients).length)    {

                        jsonUtils.render(dataOut, response, urlQuery.callback);

                    }

                } else {

                    jsonUtils.renderErrors([new Error(errors)], response, urlQuery.callback);

                }

            });

        });

    }

}

contributorStatistics.name = "Contribution Reporter";
contributorStatistics.description = "Generates JSON/JSONP with all contributors and how many contributions they made for all repositorys or the repository specified in a 'repo' parameter. For JSONP add a 'callback' parameter.";

module.exports = {
    '/contribStats': function(_repoClients) {
        repoClients = _repoClients;
        return contributorStatistics;
    }
};<commit_msg>Enforcing 82 char line length.<commit_after>var jsonUtils = require('../utils/json');
var nodeURL = require("url");
var repoClients;

function contributorStatistics (request, response)    {

    var dataOut = {},
        responseCount,
        urlQuery = nodeURL.parse(request.url, true).query;

    if(nodeURL.parse(request.url).query !== null && urlQuery.repo != "all")   {

        if (repoClients[urlQuery.repo]) {

            dataOut[urlQuery.repo] = [];

            repoClients[urlQuery.repo].github.repos.getContributors({
                "user": urlQuery.repo.split("/").shift(),
                "repo": urlQuery.repo.split("/").pop(),
                "anon": false
            }, function(errors, contribs){
                if (errors == null) {

                    dataOut[urlQuery.repo] = contribs.map(function(nextContrib){

                        return {
                            "login": nextContrib.login,
                            "contributions": nextContrib.contributions
                        };

                    });

                    jsonUtils.render(dataOut, response, urlQuery.callback);

                }
            });

        } else {

            jsonUtils.renderErrors(
                [new Error("Not monitoring this repository!")],
                response, urlQuery.callback
            );

        }

    } else {

        responseCount = 0;

        Object.keys(repoClients).forEach(function (nextRepo) {

            dataOut[nextRepo] = [];

            repoClients[nextRepo].github.repos.getContributors({
                "user": repoClients[nextRepo].toString().split("/").shift(),
                "repo": repoClients[nextRepo].toString().split("/").pop(),
                "anon": false
            }, function(errors, contribs){

                if (errors == null) {

                    dataOut[nextRepo] = contribs.map(function(nextContrib){

                        return {
                            "login": nextContrib.login,
                            "contributions": nextContrib.contributions
                        };

                    });

                    responseCount++;

                    if (responseCount >= Object.keys(repoClients).length)    {

                        jsonUtils.render(dataOut, response, urlQuery.callback);

                    }

                } else {

                    jsonUtils.renderErrors(
                        [new Error(errors)], response, urlQuery.callback
                    );

                }

            });

        });

    }

}

contributorStatistics.name = "Contribution Reporter";
contributorStatistics.description = "Generates JSON/JSONP with all contributors "
    + "and how many contributions they made for all repositorys or the "
    + "repository specified in a 'repo' parameter. For JSONP add a 'callback' "
    + "parameter.";

module.exports = {
    '/contribStats': function(_repoClients) {
        repoClients = _repoClients;
        return contributorStatistics;
    }
};<|endoftext|>


<commit_before>// dingo_test.js
//
// Class for encapsulating test information.
"use strict";

var fs = require('fs');

var dingoJobTypes = require('./dingo_job_types');
var dingoUtils = require('./dingo_utils');
var DingoJob = require('./dingo_job').DingoJob;
var DingoJobPipeline = require('./dingo_job_pipeline').DingoJobPipeline;

const DingoTest = class DingoTest {
    constructor(tenantId, subscriptionId, clientId, clientSecret, duration, delay, randomOrder) {
        this.tenantId = tenantId;
        this.subscriptionId = subscriptionId;
        this.clientId = clientId;
        this.clientSecret = clientSecret;
        this.testDuration = 0;
        this.testDelay = 0;
        this.testRandomOrder = false;

        if(duration) {
            this.testDuration = duration;
        }
        if(delay) {
            this.testDelay = delay;
        }
        if(randomOrder) {
            this.testRandomOrder = true;
        }

        this.jobs = [];
    }
}

// Add a job to the test.
DingoTest.prototype.addJob = function(job) {
    this.jobs.push(job);
}

// Display test details
DingoTest.prototype.dumpTest = function() {
    console.log("Test defined:");
    console.log("    Tenant Id:      " + this.tenantId);
    console.log("    Subcription Id: " + this.subscriptionId);
    console.log("    Client Id:      " + this.clientId);
    console.log("    Client Secret:  " + this.clientSecret);
    console.log("");
    console.log("Global properties:");
    console.log("    Test duration:  " + this.testDuration);
    console.log("    Test delay:     " + this.testDelay);
    console.log("    Random Order:   " + this.testRandomOrder);
    console.log("");
    console.log("Jobs:");
    for(var i = 0; i < this.jobs.length; i++) {
        this.jobs[i].dumpJob(4);
    }
}

// Parse the command line and create the test.
DingoTest.generateTest = function(args) {
    if(!args) {
        throw new Error('Unable to generate test.  No arguments supplied.');
    }

    // command line overrides settings in a test file
    var tenantId = args.tenant;
    var subscriptionId = args.subscription;
    var clientId = args.client;
    var clientSecret = args.password;

    var testDuration = dingoUtils.parse_argument('int-range', args.testduration, 60);
    var testDelay = dingoUtils.parse_argument('int-range', args.testdelay, 60);
    var randomOrder = args.testrandom;

    var jobs = [];

    if(args.testfile) {
        if(!args.testfile) {
            throw new Error('Unable to generate test.  No test file specified.');
        }

        var testJson;
        try {
            var testfile = fs.readFileSync(args.testfile);
            testJson = JSON.parse(testfile);
        } catch(ex) {
            throw new Error('Unable to generate test.  Failure reading test file.  File: ' + args.testfile + ', Error: ' + ex);
        }

        // validate json content, if items missing or if a command line option exists, that takes precedence
        if(!tenantId) { tenantId = testJson.tenantId; }
        if(!subscriptionId) { subscriptionId = testJson.subscriptionId; }
        if(!clientId) { clientId = testJson.clientId; }
        if(!clientSecret) { clientSecret = testJson.clientSecret; }

        // Flags for how to run test jobs.  Default is run each test once.
        if(!args.testduration && testJson.testDuration) {
            testDuration = dingoUtils.parse_argument('int-range', testJson.testDuration, 0);
        }
        if(!args.testdelay && testJson.testDelay) {
            testDelay = dingoUtils.parse_argument('int-range', testJson.testDelay, 0);
        }
        if(!randomOrder) { randomOrder = testJson.randomOrder ? testJson.randomOrder : false; }

        if((typeof testJson.jobs != 'object') && !(testJson.jobs instanceof Array)) {
            throw new Error('\'jobs\' section of test file required and conform to the valid format.');
        }
        var jobList = testJson.jobs;
        for(var i = 0; i < jobList.length; i++) {
            var j = jobList[i];
            jobs.push({
                type: j.type,
                operation: j.operation,
                resourceGroup: (args.resourcegrp ? args.resourcegrp : j.resourceGroup),
                resource: (args.resource ? (args.resource == '*' ? null : args.resource) : (j.resource == "*" ? null : j.resource)),
                resourceMatch: (args.resourcematch ? args.resourcematch : j.resourcematch),
                randomResource: (args.randomresource ? true : (j.resource == '*' ? true : false)),
                duration: dingoUtils.parse_argument('int-range', (args.duration ? args.duration : (j.duration ? j.duration : 60)), 60)
            });
        }
    } else {
        // job arguments
        var type = args.resourcetype;
        var operation = args.operation;
        var resourceGroup = args.resourcegrp;
        var resource = (args.resource == '*' ? null : args.resource);
        var resourceMatch = args.resourcematch;
        var randomResource = (args.randomresource ? true : (resource == null ? true : false));
        var duration = dingoUtils.parse_argument('int-range', args.duration, 60);
        if(!type || !operation || !resourceGroup) {
            throw new Error('Required parameters not specified.');
        }

        jobs.push({
            type: type,
            operation: operation,
            resourceGroup: resourceGroup,
            resource: resource,
            resourceMatch: resourceMatch,
            randomResource: randomResource,
            duration: duration
        });
    }

    if(!tenantId) { throw new Error('Required parameter \'tenantId\' not specified.'); }
    if(!subscriptionId) { throw new Error('Required parameter \'subscriptionId\' not specified.'); }
    if(!clientId) { throw new Error('Required parameter \'clientId\' not specified.'); }
    if(!clientSecret) { throw new Error('Required parameter \'clientSecret\' not specified.'); }

    if(jobs.length == 0) {
        throw new Error('No jobs specified.');
    }

    var test = new DingoTest(tenantId, subscriptionId, clientId, clientSecret, testDuration, testDelay, randomOrder);
    for(var i = 0; i < jobs.length; i++) {
        var j = jobs[i];
        var job = DingoJob.generateJob(j.type, j.operation, j.resourceGroup, j.resource, j.resourceMatch, j.randomResource, j.duration);
        test.addJob(job);
    }

    test.dumpTest();
    return test;
}

function randomArrayOfN(n) {
    var result = [];
    while(result.length < n) {
        var r = Math.floor(Math.random() * n);
        var found = false;
        for(var i = 0; i < result.length; i++) {
            if(r == result[i]) {
                found = true;
                break;
            }
        }
        if(!found) {
            result.push(r);
        }
    }
    return result;
}

DingoTest.processJob = function(manager, jobSequence, startTime, currentIndex) {
    var pipeline = new DingoJobPipeline(manager.tenantId,
                                        manager.subscriptionId,
                                        manager.clientId,
                                        manager.clientSecret,
                                        manager.jobs[jobSequence[currentIndex]])
    pipeline.go(function(err, result) {
        if(err) {
            throw new Error('Attempt to process job failed.  Error: ' + err);
        } else {
            if(manager.testDuration) {
                var now = Date.now();
                if(now - startTime >= (manager.testDuration * 1000)) {
                    console.log('Total test time exceeded.  Shutting down.');
                    process.exit(0);
                }
            } else if(currentIndex + 1 >= jobSequence.length) {
                console.log('All tests run.');
                process.exit(0);
            }

            if(manager.jobs[jobSequence[currentIndex]].randomOperation) {
                var updatedJob = manager.jobs[jobSequence[currentIndex]].regenerateJob();
                manager.jobs[jobSequence[currentIndex]] = updatedJob;
            }

            if(currentIndex + 1 == jobSequence.length) {
                if(manager.testRandomOrder) {
                    jobSequence = randomArrayOfN(manager.jobs.length);
                }
                currentIndex = 0;
            } else {
                currentIndex++;
            }

            setTimeout(function() {
                DingoTest.processJob(manager, jobSequence, startTime, currentIndex)
            }, manager.testDelay * 1000);
        }
    });
}

DingoTest.prototype.go = function() {
    var manager = this;
    var startTime = Date.now();

    // test details
    var jobSequence;
    if(manager.testRandomOrder) {
        jobSequence = randomArrayOfN(manager.jobs.length);
    } else {
        jobSequence = [];
        for(var i = 0; i < manager.jobs.length; i++) { jobSequence.push(i); }
    }

    DingoTest.processJob(manager, jobSequence, startTime, 0);
}

module.exports = { DingoTest };
<commit_msg>Closes #14<commit_after>// dingo_test.js
//
// Class for encapsulating test information.
"use strict";

var fs = require('fs');

var dingoJobTypes = require('./dingo_job_types');
var dingoUtils = require('./dingo_utils');
var DingoJob = require('./dingo_job').DingoJob;
var DingoJobPipeline = require('./dingo_job_pipeline').DingoJobPipeline;

const DingoTest = class DingoTest {
    constructor(tenantId, subscriptionId, clientId, clientSecret, duration, delay, randomOrder) {
        this.tenantId = tenantId;
        this.subscriptionId = subscriptionId;
        this.clientId = clientId;
        this.clientSecret = clientSecret;
        this.testDuration = 0;
        this.testDelay = 0;
        this.testRandomOrder = false;

        if(duration) {
            this.testDuration = duration;
        }
        if(delay) {
            this.testDelay = delay;
        }
        if(randomOrder) {
            this.testRandomOrder = true;
        }

        this.jobs = [];
    }
}

// Add a job to the test.
DingoTest.prototype.addJob = function(job) {
    this.jobs.push(job);
}

// Display test details
DingoTest.prototype.dumpTest = function() {
    console.log("Test defined:");
    console.log("    Tenant Id:      " + this.tenantId);
    console.log("    Subcription Id: " + this.subscriptionId);
    console.log("    Client Id:      " + this.clientId);
    console.log("    Client Secret:  " + this.clientSecret);
    console.log("");
    console.log("Global properties:");
    console.log("    Test duration:  " + this.testDuration);
    console.log("    Test delay:     " + this.testDelay);
    console.log("    Random Order:   " + this.testRandomOrder);
    console.log("");
    console.log("Jobs:");
    for(var i = 0; i < this.jobs.length; i++) {
        this.jobs[i].dumpJob(4);
    }
}

// Parse the command line and create the test.
DingoTest.generateTest = function(args) {
    if(!args) {
        throw new Error('Unable to generate test.  No arguments supplied.');
    }

    // command line overrides settings in a test file
    var tenantId = args.tenant;
    var subscriptionId = args.subscription;
    var clientId = args.client;
    var clientSecret = args.password;

    var testDuration = dingoUtils.parse_argument('int-range', args.testduration, 60);
    var testDelay = dingoUtils.parse_argument('int-range', args.testdelay, 60);
    var randomOrder = args.testrandom;

    var jobs = [];

    if(args.testfile) {
        if(!args.testfile) {
            throw new Error('Unable to generate test.  No test file specified.');
        }

        var testJson;
        try {
            var testfile = fs.readFileSync(args.testfile);
            testJson = JSON.parse(testfile);
        } catch(ex) {
            throw new Error('Unable to generate test.  Failure reading test file.  File: ' + args.testfile + ', Error: ' + ex);
        }

        // validate json content, if items missing or if a command line option exists, that takes precedence
        if(!tenantId) { tenantId = testJson.tenantId; }
        if(!subscriptionId) { subscriptionId = testJson.subscriptionId; }
        if(!clientId) { clientId = testJson.clientId; }
        if(!clientSecret) { clientSecret = testJson.clientSecret; }

        // Flags for how to run test jobs.  Default is run each test once.
        if(!args.testduration && testJson.testDuration) {
            testDuration = dingoUtils.parse_argument('int-range', testJson.testDuration, 0);
        }
        if(!args.testdelay && testJson.testDelay) {
            testDelay = dingoUtils.parse_argument('int-range', testJson.testDelay, 0);
        }
        if(!randomOrder) { randomOrder = testJson.randomOrder ? testJson.randomOrder : false; }

        if((typeof testJson.jobs != 'object') && !(testJson.jobs instanceof Array)) {
            throw new Error('\'jobs\' section of test file required and conform to the valid format.');
        }
        var jobList = testJson.jobs;

console.log("POOP");
console.log("---- " + args.resourceMa);
        for(var i = 0; i < jobList.length; i++) {
            var j = jobList[i];
console.log("++++ " + j.resourceMatch);
            jobs.push({
                type: j.type,
                operation: j.operation,
                resourceGroup: (args.resourcegrp ? args.resourcegrp : j.resourceGroup),
                resource: (args.resource ? (args.resource == '*' ? null : args.resource) : (j.resource == "*" ? null : j.resource)),
                resourceMatch: (args.resourcematch ? args.resourcematch : j.resourceMatch),
                randomResource: (args.randomresource ? true : (j.resource == '*' ? true : false)),
                duration: dingoUtils.parse_argument('int-range', (args.duration ? args.duration : (j.duration ? j.duration : 60)), 60)
            });
        }
    } else {
        // job arguments
        var type = args.resourcetype;
        var operation = args.operation;
        var resourceGroup = args.resourcegrp;
        var resource = (args.resource == '*' ? null : args.resource);
        var resourceMatch = args.resourcematch;
        var randomResource = (args.randomresource ? true : (resource == null ? true : false));
        var duration = dingoUtils.parse_argument('int-range', args.duration, 60);
        if(!type || !operation || !resourceGroup) {
            throw new Error('Required parameters not specified.');
        }

        jobs.push({
            type: type,
            operation: operation,
            resourceGroup: resourceGroup,
            resource: resource,
            resourceMatch: resourceMatch,
            randomResource: randomResource,
            duration: duration
        });
    }

    if(!tenantId) { throw new Error('Required parameter \'tenantId\' not specified.'); }
    if(!subscriptionId) { throw new Error('Required parameter \'subscriptionId\' not specified.'); }
    if(!clientId) { throw new Error('Required parameter \'clientId\' not specified.'); }
    if(!clientSecret) { throw new Error('Required parameter \'clientSecret\' not specified.'); }

    if(jobs.length == 0) {
        throw new Error('No jobs specified.');
    }

    var test = new DingoTest(tenantId, subscriptionId, clientId, clientSecret, testDuration, testDelay, randomOrder);
    for(var i = 0; i < jobs.length; i++) {
        var j = jobs[i];
        var job = DingoJob.generateJob(j.type, j.operation, j.resourceGroup, j.resource, j.resourceMatch, j.randomResource, j.duration);
        test.addJob(job);
    }

    test.dumpTest();
    return test;
}

function randomArrayOfN(n) {
    var result = [];
    while(result.length < n) {
        var r = Math.floor(Math.random() * n);
        var found = false;
        for(var i = 0; i < result.length; i++) {
            if(r == result[i]) {
                found = true;
                break;
            }
        }
        if(!found) {
            result.push(r);
        }
    }
    return result;
}

DingoTest.processJob = function(manager, jobSequence, startTime, currentIndex) {
    var pipeline = new DingoJobPipeline(manager.tenantId,
                                        manager.subscriptionId,
                                        manager.clientId,
                                        manager.clientSecret,
                                        manager.jobs[jobSequence[currentIndex]])
    pipeline.go(function(err, result) {
        if(err) {
            throw new Error('Attempt to process job failed.  Error: ' + err);
        } else {
            if(manager.testDuration) {
                var now = Date.now();
                if(now - startTime >= (manager.testDuration * 1000)) {
                    console.log('Total test time exceeded.  Shutting down.');
                    process.exit(0);
                }
            } else if(currentIndex + 1 >= jobSequence.length) {
                console.log('All tests run.');
                process.exit(0);
            }

            if(manager.jobs[jobSequence[currentIndex]].randomOperation) {
                var updatedJob = manager.jobs[jobSequence[currentIndex]].regenerateJob();
                manager.jobs[jobSequence[currentIndex]] = updatedJob;
            }

            if(currentIndex + 1 == jobSequence.length) {
                if(manager.testRandomOrder) {
                    jobSequence = randomArrayOfN(manager.jobs.length);
                }
                currentIndex = 0;
            } else {
                currentIndex++;
            }

            setTimeout(function() {
                DingoTest.processJob(manager, jobSequence, startTime, currentIndex)
            }, manager.testDelay * 1000);
        }
    });
}

DingoTest.prototype.go = function() {
    var manager = this;
    var startTime = Date.now();

    // test details
    var jobSequence;
    if(manager.testRandomOrder) {
        jobSequence = randomArrayOfN(manager.jobs.length);
    } else {
        jobSequence = [];
        for(var i = 0; i < manager.jobs.length; i++) { jobSequence.push(i); }
    }

    DingoTest.processJob(manager, jobSequence, startTime, 0);
}

module.exports = { DingoTest };
<|endoftext|>


<commit_before>/**
 * @tag controllers, home
 */
$.Controller.extend('Surveybuilder.Controllers.Tabs',
/* @Static */
{
    onDocument: false
},
/* @Prototype */
{
	updateTitle: function(line) {
    	$('#surveyBuilderTabs a[href="#' + line.id + '"]').children().text(line.title);
    },

    init: function(){
    	steal.dev.log('new tabs controller instance created');
    	//TODO: using this.element.tabs() does the initial tab-ification of the
    	//tabs, but does not attach the jquery id to the element, and so future
    	//calls to the tabs() function fail.  For now using the id for selection,
    	//but this does not make sense on a prototype init
    	$('#surveyBuilderTabs').tabs({
		    tabTemplate: '
#{label}
',
		    add: function(event, ui) {
		        $('#surveyBuilderTabs').tabs('select', '#' + ui.panel.id);
		    }
		});

        // Make tabs able to receive lines dropped on them
        $(".ui-tabs-nav").droppable({
		    accept: '.line',
		    hoverClass: 'tab-hover',
		    drop: function(event, ui) {
		        var lineId = ui.draggable.attr("data-line");
		        OpenAjax.hub.publish('tabs.openLine', {id:lineId});
		    }
		});
    },

    'tabs.openLine subscribe': function(event, params) {
    	this.openLineInTab(params.id);
    },

    /**
     * Open up a Line in the tabs
     * @param {Number} id the Line to open
     */
    openLineInTab: function(id){
        var currentLine = Line.findOne({id:id});
        if ($('#'+id).length) {
            // line already open
            return;
        }
        var tabsDiv = $('#surveyBuilderTabs');
        tabsDiv.append($.View('//surveybuilder/views/line/show', {line:currentLine}));
        tabsDiv.tabs('add' , "#"+id , currentLine.title);
        // add line-controller to newly opened line
        $('#'+id).surveybuilder_line();
        // add controllers to each newly rendered lineitem
        $('#'+id + ' .lineitem').surveybuilder_lineitem();
        $('#'+id + ' .logicComponent').surveybuilder_logic_component();
        $('#'+id + ' .branch').each(function() {
        	line = Line.findOne({id:$(this).attr('data-line')});
        	$(this).surveybuilder_branch({model:line});
        });
    },

    'tabs.close subscribe': function(event, params) {
    	this.closeTabById(params.id);
    },

    /**
     * Close a tab
     * @param {Number} id the tab to close
     */
    closeTabById: function(id){
        var tabsDiv = $('#surveyBuilderTabs');
        var fullId = '#' + id;

        $('#surveyBuilderTabs .ui-tabs-nav li').each(function(index){
            if ($(this).children(':first').attr("href") === fullId){  // TODO better way of selecting that isn't as brittle or slow
                tabsDiv.tabs('remove', index);
                return;
            }
        });
    },
    ".ui-icon-document click": function(el, ev){
        OpenAjax.hub.publish('survey.export', {});
        ev.stopPropagation();
    },
    "#saveExport click" : function(el, ev){
        window.open("data:text/plain," + encodeURIComponent($('#export textarea').val()));
    },
    '.close-tab click' : function(el, ev){
        if ($(el).siblings().find('.changes-made:visible').length > 0){
            if(confirm("close without saving changes?")) {
                var tabs = $('#surveyBuilderTabs');
                var lineId = $('.ui-tabs-selected a').attr('href').replace('#', '');
                OpenAjax.hub.publish('line.discardChanges', {id:lineId});
                //OpenAjax.hub.publish('survey.render', {});
                tabs.tabs('remove', tabs.tabs('option', 'selected'));
            }
        }
        else{
            var tabs = $('#surveyBuilderTabs');
            tabs.tabs('remove', tabs.tabs('option', 'selected'));
        }
        ev.stopPropagation();
    },

    /**
     * Collection of subscriptions for events that should mark the tab as changed
     */

    'survey.created subscribe': function() {
    	steal.dev.log("Tabs: survey.updated");
    	this.markTabAsChanged('survey');
    	OpenAjax.hub.publish('buttons.enableSaveButton', {});
    },

    'survey.updated subscribe': function() {
    	steal.dev.log("Tabs: survey.updated");
    	this.markTabAsChanged('survey');
    	OpenAjax.hub.publish('buttons.enableSaveButton', {});
    },

    'line.updated subscribe': function(event, line) {
    	steal.dev.log("Tabs: line.updated");
		this.updateTitle(line);
    	this.markTabAsChanged(line.id);
    	OpenAjax.hub.publish('buttons.enableSaveButton', {});
    },

    'line.destroyed subscribe': function(event, params) {
    	steal.dev.log("Tabs: line.destroy");
    	OpenAjax.hub.publish('buttons.enableSaveButton', {});
    },

    'lineitem.updated subscribe': function() {
    	steal.dev.log("Tabs: lineitem.updated");
    	this.markCurrentTabAsChanged();
    	OpenAjax.hub.publish('buttons.enableSaveButton', {});
    },

    'lineitem.destroyed subscribe': function() {
    	steal.dev.log("Tabs: lineitem.destroy");
    	this.markCurrentTabAsChanged();
    	OpenAjax.hub.publish('buttons.enableSaveButton', {});
    },

    'tabs.markTabAsChanged subscribe': function(event, params) {
    	this.markTabAsChanged(params.id);
    },
    /**
     * Mark a tab as changed
     * @param {Number} id the id of the tab to change
     */
    markTabAsChanged: function(id){
    	$('#surveyBuilderTabs a[href="#' + id + '"]').siblings('.ui-icon-gear').show();
    	OpenAjax.hub.publish('buttons.enableSaveButton', {});
    },

    'survey.loadFinished subscribe': function(event, params) {
    	this.markTabsAsUnchanged();
    },

    'tabs.markTabsAsUnchanged subscribe': function(event, params) {
    	this.markTabsAsUnchanged();
    },

    /**
     * Remove all changed indicators from tabs
     */
    markTabsAsUnchanged: function() {
    	$('.ui-icon-gear').hide();
    },

    /**
     * Mark the currently selected tab as changed
     */
    markCurrentTabAsChanged: function(){
       $('.ui-tabs-selected .ui-icon-gear').show();
    }

});
<commit_msg>reposition tab content as the tab navbar grows and shrinks<commit_after>/**
 * @tag controllers, home
 */
$.Controller.extend('Surveybuilder.Controllers.Tabs',
/* @Static */
{
    onDocument: false
},
/* @Prototype */
{
	updateTitle: function(line) {
    	$('#surveyBuilderTabs a[href="#' + line.id + '"]').children().text(line.title);
    },

    init: function(){
    	steal.dev.log('new tabs controller instance created');
    	//TODO: using this.element.tabs() does the initial tab-ification of the
    	//tabs, but does not attach the jquery id to the element, and so future
    	//calls to the tabs() function fail.  For now using the id for selection,
    	//but this does not make sense on a prototype init
    	$('#surveyBuilderTabs').tabs({
		    tabTemplate: '
#{label}
',
		    add: function(event, ui) {
		        $('#surveyBuilderTabs').tabs('select', '#' + ui.panel.id);
		    }
		});

        // Make tabs able to receive lines dropped on them
        $(".ui-tabs-nav").droppable({
		    accept: '.line',
		    hoverClass: 'tab-hover',
		    drop: function(event, ui) {
		        var lineId = ui.draggable.attr("data-line");
		        OpenAjax.hub.publish('tabs.openLine', {id:lineId});
		    }
		});
    },

    /**
     * Reposition the tabs-container based off the tab list height
     */
    repositionTabContent: function() {
    	$("#tabs-container").css("top", ($("#buttons").innerHeight() + this.element.innerHeight()) + "px");
    },

    "{window} resize": function() {
    	this.repositionTabContent();
    },

    'tabs.openLine subscribe': function(event, params) {
    	this.openLineInTab(params.id);
    },

    /**
     * Open up a Line in the tabs
     * @param {Number} id the Line to open
     */
    openLineInTab: function(id){
        var currentLine = Line.findOne({id:id});
        if ($('#'+id).length) {
            // line already open
            return;
        }
        var tabsDiv = $('#surveyBuilderTabs');
        tabsDiv.append($.View('//surveybuilder/views/line/show', {line:currentLine}));
        tabsDiv.tabs('add' , "#"+id , currentLine.title);
        // add line-controller to newly opened line
        $('#'+id).surveybuilder_line();
        // add controllers to each newly rendered lineitem
        $('#'+id + ' .lineitem').surveybuilder_lineitem();
        $('#'+id + ' .logicComponent').surveybuilder_logic_component();
        $('#'+id + ' .branch').each(function() {
        	line = Line.findOne({id:$(this).attr('data-line')});
        	$(this).surveybuilder_branch({model:line});
        });

        this.repositionTabContent();
    },

    'tabs.close subscribe': function(event, params) {
    	this.closeTabById(params.id);
    },

    /**
     * Close a tab
     * @param {Number} id the tab to close
     */
    closeTabById: function(id){
        var tabsDiv = $('#surveyBuilderTabs');
        var fullId = '#' + id;

        $('#surveyBuilderTabs .ui-tabs-nav li').each(function(index){
            if ($(this).children(':first').attr("href") === fullId){  // TODO better way of selecting that isn't as brittle or slow
                tabsDiv.tabs('remove', index);
                return;
            }
        });
        this.repositionTabContent();
    },
    ".ui-icon-document click": function(el, ev){
        OpenAjax.hub.publish('survey.export', {});
        ev.stopPropagation();
    },
    "#saveExport click" : function(el, ev){
        window.open("data:text/plain," + encodeURIComponent($('#export textarea').val()));
    },
    '.close-tab click' : function(el, ev){
        if ($(el).siblings().find('.changes-made:visible').length > 0){
            if(confirm("close without saving changes?")) {
                var tabs = $('#surveyBuilderTabs');
                var lineId = $('.ui-tabs-selected a').attr('href').replace('#', '');
                OpenAjax.hub.publish('line.discardChanges', {id:lineId});
                //OpenAjax.hub.publish('survey.render', {});
                tabs.tabs('remove', tabs.tabs('option', 'selected'));
            }
        }
        else{
            var tabs = $('#surveyBuilderTabs');
            tabs.tabs('remove', tabs.tabs('option', 'selected'));
        }
        this.repositionTabContent();
        ev.stopPropagation();
    },

    /**
     * Collection of subscriptions for events that should mark the tab as changed
     */

    'survey.created subscribe': function() {
    	steal.dev.log("Tabs: survey.updated");
    	this.markTabAsChanged('survey');
    	OpenAjax.hub.publish('buttons.enableSaveButton', {});
    },

    'survey.updated subscribe': function() {
    	steal.dev.log("Tabs: survey.updated");
    	this.markTabAsChanged('survey');
    	OpenAjax.hub.publish('buttons.enableSaveButton', {});
    },

    'line.updated subscribe': function(event, line) {
    	steal.dev.log("Tabs: line.updated");
		this.updateTitle(line);
    	this.markTabAsChanged(line.id);
    	OpenAjax.hub.publish('buttons.enableSaveButton', {});
    },

    'line.destroyed subscribe': function(event, params) {
    	steal.dev.log("Tabs: line.destroy");
    	OpenAjax.hub.publish('buttons.enableSaveButton', {});
    },

    'lineitem.updated subscribe': function() {
    	steal.dev.log("Tabs: lineitem.updated");
    	this.markCurrentTabAsChanged();
    	OpenAjax.hub.publish('buttons.enableSaveButton', {});
    },

    'lineitem.destroyed subscribe': function() {
    	steal.dev.log("Tabs: lineitem.destroy");
    	this.markCurrentTabAsChanged();
    	OpenAjax.hub.publish('buttons.enableSaveButton', {});
    },

    'tabs.markTabAsChanged subscribe': function(event, params) {
    	this.markTabAsChanged(params.id);
    },
    /**
     * Mark a tab as changed
     * @param {Number} id the id of the tab to change
     */
    markTabAsChanged: function(id){
    	$('#surveyBuilderTabs a[href="#' + id + '"]').siblings('.ui-icon-gear').show();
    	OpenAjax.hub.publish('buttons.enableSaveButton', {});
    },

    'survey.loadFinished subscribe': function(event, params) {
    	this.markTabsAsUnchanged();
    },

    'tabs.markTabsAsUnchanged subscribe': function(event, params) {
    	this.markTabsAsUnchanged();
    },

    /**
     * Remove all changed indicators from tabs
     */
    markTabsAsUnchanged: function() {
    	$('.ui-icon-gear').hide();
    },

    /**
     * Mark the currently selected tab as changed
     */
    markCurrentTabAsChanged: function(){
       $('.ui-tabs-selected .ui-icon-gear').show();
    }

});
<|endoftext|>


<commit_before>(function ($, Modules) {
  'use strict'
  Modules.DatetimeRelative = function () {
    this.start = function ($element) {
      var originalText = $element.text().trim()
      var dateTime = $element.attr('datetime')
      var timestamp = Date.parse(dateTime)
      if (isNaN(timestamp) === false) {
        $element.text(
          timeUntil(new Date(dateTime))
        )
      }
    }

    // Forked from https://github.com/github/time-elements
    var timeUntil = function (date) {
      var ms = date.getTime() - new Date().getTime()

      var sec = Math.round(ms / 1000)
      var min = Math.round(sec / 60)
      var hr = Math.round(min / 60)
      var day = Math.round(hr / 24)
      var month = Math.round(day / 30)
      var year = Math.round(month / 12)

      if (month >= 18) {
        return year + ' years from now'
      } else if (month >= 12) {
        return 'a year from now'
      } else if (day >= 45) {
        return month + ' months from now'
      } else if (day >= 30) {
        return 'a month from now'
      } else if (hr >= 36) {
        return day + ' days from now'
      } else if (hr >= 24) {
        return 'a day from now'
      } else if (Math.abs(month) >= 45) {
        return Math.abs(month) + ' months ago'
      } else if (day < 0) {
        return Math.abs(day) + ' days ago'
      } else {
        return 'now'
      }
    }
  }
})(window.jQuery, window.GOVUK.Modules)
<commit_msg>Show months if more than 45 days ago<commit_after>(function ($, Modules) {
  'use strict'
  Modules.DatetimeRelative = function () {
    this.start = function ($element) {
      var originalText = $element.text().trim()
      var dateTime = $element.attr('datetime')
      var timestamp = Date.parse(dateTime)
      if (isNaN(timestamp) === false) {
        $element.text(
          timeUntil(new Date(dateTime))
        )
      }
    }

    // Forked from https://github.com/github/time-elements
    var timeUntil = function (date) {
      var ms = date.getTime() - new Date().getTime()

      var sec = Math.round(ms / 1000)
      var min = Math.round(sec / 60)
      var hr = Math.round(min / 60)
      var day = Math.round(hr / 24)
      var month = Math.round(day / 30)
      var year = Math.round(month / 12)

      if (month >= 18) {
        return year + ' years from now'
      } else if (month >= 12) {
        return 'a year from now'
      } else if (day >= 45) {
        return month + ' months from now'
      } else if (day >= 30) {
        return 'a month from now'
      } else if (hr >= 36) {
        return day + ' days from now'
      } else if (hr >= 24) {
        return 'a day from now'
      } else if (Math.abs(day) >= 45) {
        return Math.abs(month) + ' months ago'
      } else if (day < 0) {
        return Math.abs(day) + ' days ago'
      } else {
        return 'now'
      }
    }
  }
})(window.jQuery, window.GOVUK.Modules)
<|endoftext|>


<commit_before>var Alert = require('alert')
var analytics = require('analytics')
var log = require('./client/log')('feedback-modal')
var modal = require('./client/modal')
var request = require('./client/request')
var session = require('session')

/**
 * Expose `Modal`
 */

var Modal = module.exports = modal({
  closable: true,
  template: require('./template.html')
})

/**
 * Submit
 */

Modal.prototype.submit = function (e) {
  e.preventDefault()
  var alerts = this.find('.alerts')
  var button = this.find('button')
  var textarea = this.find('textarea')
  var feedback = textarea.value + ''
  var results = this.model.toJSON ? this.model.toJSON() : {}
  var self = this

  button.disabled = true
  if (!feedback || feedback.length < 1) {
    alerts.appendChild(Alert({
      type: 'warning',
      text: 'Please fill in the feedback field below.'
    }).el)
  } else {
    var data = {
      feedback: feedback,
      plan: session.plan().generateQuery(),
      results: results
    }

    request.post('/feedback', data, function (err) {
      if (err) {
        log.error('%e', err)
        alerts.appendChild(Alert({
          type: 'danger',
          text: 'Failed to submit feedback.'
        }).el)
        button.disabled = false
      } else {
        analytics.track('Submitted Feedback', data)

        alerts.appendChild(Alert({
          type: 'success',
          text: 'Thanks! We appreciate the feedback!'
        }).el)

        setTimeout(function () {
          self.hide()
        }, 2500)
      }
    })
  }
}
<commit_msg>Hide feedback modal 0.5 seconds faster<commit_after>var Alert = require('alert')
var analytics = require('analytics')
var log = require('./client/log')('feedback-modal')
var modal = require('./client/modal')
var request = require('./client/request')
var session = require('session')

/**
 * Expose `Modal`
 */

var Modal = module.exports = modal({
  closable: true,
  template: require('./template.html')
})

/**
 * Submit
 */

Modal.prototype.submit = function (e) {
  e.preventDefault()
  var alerts = this.find('.alerts')
  var button = this.find('button')
  var textarea = this.find('textarea')
  var feedback = textarea.value + ''
  var results = this.model.toJSON ? this.model.toJSON() : {}
  var self = this

  button.disabled = true
  if (!feedback || feedback.length < 1) {
    alerts.appendChild(Alert({
      type: 'warning',
      text: 'Please fill in the feedback field below.'
    }).el)
  } else {
    var data = {
      feedback: feedback,
      plan: session.plan().generateQuery(),
      results: results
    }

    request.post('/feedback', data, function (err) {
      if (err) {
        log.error('%e', err)
        alerts.appendChild(Alert({
          type: 'danger',
          text: 'Failed to submit feedback.'
        }).el)
        button.disabled = false
      } else {
        analytics.track('Submitted Feedback', data)

        alerts.appendChild(Alert({
          type: 'success',
          text: 'Thanks! We appreciate the feedback!'
        }).el)

        setTimeout(function () {
          self.hide()
        }, 2000)
      }
    })
  }
}
<|endoftext|>


<commit_before>// @require Auger.Event
window.Auger || (window.Auger = {});
Auger.Dispatcher = {_actions: []};
Auger.Dispatcher._onhashchange = function(e){ 	// gets detached (avoid unnecessary closure)
	if(!e)e=window.event;
	var a=Auger.Dispatcher._actions;
	var h=Auger.Dispatcher.getHash();
	for(var i=0;i<a.length;++i){
		var v = null, t = a[i][1];
		switch(a[i][0]){
			case 0: v=true; break;
			case 1: v=(h.indexOf(t)==0?h.split(t.charAt(t.length-1)):null); break;
			case 2: v=h.match(t); break;
			case 3: try{v=t(h);}catch(x){v=null;}; break;
		}
		if(v) try{ 	// don't let the errors of one dispatched method keep the others from executing
			a[i][2].call(this, e, h, v); 	// call as a method on the element and send event (for consistency)
		}catch(x){}
	}
};
// prefix string, regex, or boolean function (allows multiple "apps" on the same page)
Auger.Dispatcher._dispatch_types = [null, 'string', RegExp, Function];
Auger.Dispatcher.dispatch = function(c,f){
	var a = Auger.Dispatcher; 	// this
	var t = a._dispatch_types, d = null;
	if(!f)
		d = [0,null,c];
	else if(typeof(c) == 'string')
		d = [1,c,f];
	else
		for(var i=2; i<t.length; ++i)
			if(c instanceof t[i])
				d = [i,c,f];
	if(d)
		a._actions.push(d);
	else
		throw("Unknown argument: " + c);
	if(a._actions.length == 1){ 	// only add it the first time since we roll through all the possibilities
		a.listen('hashchange', a._onhashchange);
		a.listen('load', a._onhashchange); 		// if the window has already loaded this probably won't run
	}
};
Auger.Dispatcher.getHash = function(){
	// location.hash gets url-decoded which could interfere with parsing
	return location.href.replace(/^[^#]*#/,'');
};
Auger.Dispatcher.setHash = function(h){
	if(!h)h='';
	if(h.charAt(0) != '#') h = '#'+h;
	location.hash = h;
};
Auger.Dispatcher.listen = function(e,f){ 			// override with desired event library
	var oe = 'on'+e;
	if(Auger.Event) Auger.Event.add(window, e, f);
	else if(oe in window) window[oe] = f;
	else throw('Event library required if window does not support '+oe);
}
<commit_msg>Change detached function name from _onhashchange to _perform<commit_after>// @require Auger.Event
window.Auger || (window.Auger = {});
Auger.Dispatcher = {_actions: []};
Auger.Dispatcher._perform = function(e){ 	// gets detached (avoid unnecessary closure)
	if(!e)e=window.event;
	var a=Auger.Dispatcher._actions;
	var h=Auger.Dispatcher.getHash();
	for(var i=0;i<a.length;++i){
		var v = null, t = a[i][1];
		switch(a[i][0]){
			case 0: v=true; break;
			case 1: v=(h.indexOf(t)==0?h.split(t.charAt(t.length-1)):null); break;
			case 2: v=h.match(t); break;
			case 3: try{v=t(h);}catch(x){v=null;}; break;
		}
		if(v) try{ 	// don't let the errors of one dispatched method keep the others from executing
			a[i][2].call(this, e, h, v); 	// call as a method on the element and send event (for consistency)
		}catch(x){}
	}
};
// prefix string, regex, or boolean function (allows multiple "apps" on the same page)
Auger.Dispatcher._dispatch_types = [null, 'string', RegExp, Function];
Auger.Dispatcher.dispatch = function(c,f){
	var a = Auger.Dispatcher; 	// this
	var t = a._dispatch_types, d = null;
	if(!f)
		d = [0,null,c];
	else if(typeof(c) == 'string')
		d = [1,c,f];
	else
		for(var i=2; i<t.length; ++i)
			if(c instanceof t[i])
				d = [i,c,f];
	if(d)
		a._actions.push(d);
	else
		throw("Unknown argument: " + c);
	if(a._actions.length == 1){ 	// only add it the first time since we roll through all the possibilities
		a.listen('hashchange', a._perform);
		a.listen('load', a._perform); 		// if the window has already loaded this probably won't run
	}
};
Auger.Dispatcher.getHash = function(){
	// location.hash gets url-decoded which could interfere with parsing
	return location.href.replace(/^[^#]*#/,'');
};
Auger.Dispatcher.setHash = function(h){
	if(!h)h='';
	if(h.charAt(0) != '#') h = '#'+h;
	location.hash = h;
};
Auger.Dispatcher.listen = function(e,f){ 			// override with desired event library
	var oe = 'on'+e;
	if(Auger.Event) Auger.Event.add(window, e, f);
	else if(oe in window) window[oe] = f;
	else throw('Event library required if window does not support '+oe);
}
<|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.
 */

/* global window, dagTZ, moment, convertSecsToHumanReadable */

// We don't re-import moment again, otherwise webpack will include it twice in the bundle!
import { escapeHtml } from './main';
import { defaultFormat, formatDateTime } from './datetime-utils';

function makeDateTimeHTML(start, end) {
  // check task ended or not
  const isEnded = end && end instanceof moment && end.isValid();
  return `Started: ${start.format(defaultFormat)}<br>Ended: ${isEnded ? end.format(defaultFormat) : 'Not ended yet'}<br>`;
}

function generateTooltipDateTimes(startDate, endDate, dagTZ) {
  if (!startDate) {
    return '
Not yet started';
  }

  const tzFormat = 'z (Z)';
  const localTZ = moment.defaultZone.name;
  startDate = moment.utc(startDate);
  endDate = moment.utc(endDate);
  dagTZ = dagTZ.toUpperCase();

  // Generate UTC Start and End Date
  let tooltipHTML = '
UTC:
';
  tooltipHTML += makeDateTimeHTML(startDate, endDate);

  // Generate User's Local Start and End Date
  startDate.tz(localTZ);
  tooltipHTML += `<br><strong>Local: ${startDate.format(tzFormat)}</strong><br>`;
  const localEndDate = endDate && endDate instanceof moment ? endDate.tz(localTZ) : endDate;
  tooltipHTML += makeDateTimeHTML(startDate, localEndDate);

  // Generate DAG's Start and End Date
  if (dagTZ !== 'UTC' && dagTZ !== localTZ) {
    startDate.tz(dagTZ);
    tooltipHTML += `<br><strong>DAG's TZ: ${startDate.format(tzFormat)}</strong><br>`;
    const dagTZEndDate = endDate && endDate instanceof moment ? endDate.tz(dagTZ) : endDate;
    tooltipHTML += makeDateTimeHTML(startDate, dagTZEndDate);
  }

  return tooltipHTML;
}

export default function tiTooltip(ti, { includeTryNumber = false } = {}) {
  let tt = '';
  if (ti.state !== undefined) {
    tt += `<strong>Status:</strong> ${escapeHtml(ti.state)}<br><br>`;
  }
  if (ti.task_id !== undefined) {
    tt += `Task_id: ${escapeHtml(ti.task_id)}<br>`;
  }
  tt += `Run: ${formatDateTime(ti.execution_date)}<br>`;
  if (ti.run_id !== undefined) {
    tt += `Run Id: <nobr>${escapeHtml(ti.run_id)}</nobr><br>`;
  }
  if (ti.operator !== undefined) {
    tt += `Operator: ${escapeHtml(ti.operator)}<br>`;
  }
  // Don't translate/format this, keep it as the full ISO8601 date
  if (ti.start_date instanceof moment) {
    tt += `Started: ${escapeHtml(ti.start_date.toISOString())}<br>`;
  } else {
    tt += `Started: ${escapeHtml(ti.start_date)}<br>`;
  }
  // Calculate duration on the fly if task instance is still running
  if (ti.state === 'running') {
    const startDate = ti.start_date instanceof moment ? ti.start_date : moment(ti.start_date);
    ti.duration = moment().diff(startDate, 'second');
  }

  tt += `Duration: ${escapeHtml(convertSecsToHumanReadable(ti.duration))}<br>`;

  if (includeTryNumber) {
    tt += `Try Number: ${escapeHtml(ti.try_number)}<br>`;
  }
  // dagTZ has been defined in dag.html
  tt += generateTooltipDateTimes(ti.start_date, ti.end_date, dagTZ);
  return tt;
}

export function taskNoInstanceTooltip(taskId, task) {
  let tt = '';
  if (taskId) {
    tt += `Task_id: ${escapeHtml(taskId)}<br>`;
  }
  if (task.task_type !== undefined) {
    tt += `Operator: ${escapeHtml(task.task_type)}<br>`;
  }
  tt += '
DAG has yet to run.';
  return tt;
}

window.tiTooltip = tiTooltip;
window.taskNoInstanceTooltip = taskNoInstanceTooltip;
<commit_msg>Only show User's local timezone if it's not UTC (#13904)<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.
 */

/* global window, dagTZ, moment, convertSecsToHumanReadable */

// We don't re-import moment again, otherwise webpack will include it twice in the bundle!
import { escapeHtml } from './main';
import { defaultFormat, formatDateTime } from './datetime-utils';

function makeDateTimeHTML(start, end) {
  // check task ended or not
  const isEnded = end && end instanceof moment && end.isValid();
  return `Started: ${start.format(defaultFormat)}<br>Ended: ${isEnded ? end.format(defaultFormat) : 'Not ended yet'}<br>`;
}

function generateTooltipDateTimes(startDate, endDate, dagTZ) {
  if (!startDate) {
    return '
Not yet started';
  }

  const tzFormat = 'z (Z)';
  const localTZ = moment.defaultZone.name;
  startDate = moment.utc(startDate);
  endDate = moment.utc(endDate);
  dagTZ = dagTZ.toUpperCase();

  // Generate UTC Start and End Date
  let tooltipHTML = '
UTC:
';
  tooltipHTML += makeDateTimeHTML(startDate, endDate);

  // Generate User's Local Start and End Date, unless it's UTC
  if (localTZ !== 'UTC') {
    startDate.tz(localTZ);
    tooltipHTML += `<br><strong>Local: ${startDate.format(tzFormat)}</strong><br>`;
    const localEndDate = endDate && endDate instanceof moment ? endDate.tz(localTZ) : endDate;
    tooltipHTML += makeDateTimeHTML(startDate, localEndDate);
  }

  // Generate DAG's Start and End Date
  if (dagTZ !== 'UTC' && dagTZ !== localTZ) {
    startDate.tz(dagTZ);
    tooltipHTML += `<br><strong>DAG's TZ: ${startDate.format(tzFormat)}</strong><br>`;
    const dagTZEndDate = endDate && endDate instanceof moment ? endDate.tz(dagTZ) : endDate;
    tooltipHTML += makeDateTimeHTML(startDate, dagTZEndDate);
  }

  return tooltipHTML;
}

export default function tiTooltip(ti, { includeTryNumber = false } = {}) {
  let tt = '';
  if (ti.state !== undefined) {
    tt += `<strong>Status:</strong> ${escapeHtml(ti.state)}<br><br>`;
  }
  if (ti.task_id !== undefined) {
    tt += `Task_id: ${escapeHtml(ti.task_id)}<br>`;
  }
  tt += `Run: ${formatDateTime(ti.execution_date)}<br>`;
  if (ti.run_id !== undefined) {
    tt += `Run Id: <nobr>${escapeHtml(ti.run_id)}</nobr><br>`;
  }
  if (ti.operator !== undefined) {
    tt += `Operator: ${escapeHtml(ti.operator)}<br>`;
  }
  // Don't translate/format this, keep it as the full ISO8601 date
  if (ti.start_date instanceof moment) {
    tt += `Started: ${escapeHtml(ti.start_date.toISOString())}<br>`;
  } else {
    tt += `Started: ${escapeHtml(ti.start_date)}<br>`;
  }
  // Calculate duration on the fly if task instance is still running
  if (ti.state === 'running') {
    const startDate = ti.start_date instanceof moment ? ti.start_date : moment(ti.start_date);
    ti.duration = moment().diff(startDate, 'second');
  }

  tt += `Duration: ${escapeHtml(convertSecsToHumanReadable(ti.duration))}<br>`;

  if (includeTryNumber) {
    tt += `Try Number: ${escapeHtml(ti.try_number)}<br>`;
  }
  // dagTZ has been defined in dag.html
  tt += generateTooltipDateTimes(ti.start_date, ti.end_date, dagTZ);
  return tt;
}

export function taskNoInstanceTooltip(taskId, task) {
  let tt = '';
  if (taskId) {
    tt += `Task_id: ${escapeHtml(taskId)}<br>`;
  }
  if (task.task_type !== undefined) {
    tt += `Operator: ${escapeHtml(task.task_type)}<br>`;
  }
  tt += '
DAG has yet to run.';
  return tt;
}

window.tiTooltip = tiTooltip;
window.taskNoInstanceTooltip = taskNoInstanceTooltip;
<|endoftext|>