<commit_before>/**
 * Created by justin.baize on 6/16/16.
 */

'use strict'
var fs = require('fs');
var _  = require('lodash');

var theCompetitionMat  = []
var winnersBracket     = []
var losersBracket      = []
var firstCompetitorsProbabilityOfVictory  = 0
var secondCompetitorsProbabilityOfVictory = 0
var numberOfRequiredRounds = 4

var k = 16
var n = 1

/**
 * @name matPopulator
 * @description - Takes two competitors from arrayOfCompetitors and
 *                puts them into theCompetitionMat array.
 * @param arrayOfCompetitors
 **/

var outputArr = []

var tournamentRegistrator = function(number) {

  var allCompetitorsObj = {}
  var squared = number * number
  var prototypeCompetitor = {rating: 1600, wins: 0, losses: 0}

  //this will output an object with
  //competitors === squared
  //outputObj: {
  //             c(n): { rating: 1600, wins: 0, losses: 0 },
  //             c(n+1): { rating: 1600, wins: 0, losses: 0 },
  //             c(n+2): { rating: 1600, wins: 0, losses: 0 },
  //           }
  var competitorCreator = function (squared) {
    var tempArr = []
    var tempArr2 = []

    for (var j = 1; j <= squared; j++) {
      var yourNumber = j.toString()
      var name = "c" + yourNumber
      var competitorAssembler = '{"c' + yourNumber +'":{"rating":1600,"wins":0,"losses":0}}'

      // console.log("competitorAssembler:",competitorAssembler)
      // console.log("typeof competitorAssembler:",typeof competitorAssembler)

      // console.log("JSON.parse(competitorAssembler):",JSON.parse(competitorAssembler))
      // console.log("typeof JSON.parse(competitorAssembler):",typeof JSON.parse(competitorAssembler))

      // this is the goal
      // '{"c1":{"rating":1600,"wins":0,"losses":0}}'

      outputArr.push(JSON.parse(competitorAssembler))
      // tempArr2.push(prototypeCompetitor)
    }
    console.log("outputArr:",outputArr)
    // allCompetitorsObj = _.zipObject(tempArr, tempArr2)
  }

  competitorCreator(squared)

  var bullPenCreator = function(object){

    var bullPen = []

    console.log("from bullPenCreator --> object:",object)

    var competitorsList = JSON.stringify(object)

    var arrayifiedCompetitorsList = "["+competitorsList.slice(1,competitorsList.length-2)+"]"
    // console.log("JSON.parse on arrayifiedCompetitorsList:",JSON.parse("["+arrayifiedCompetitorsList+"]"))
    // console.log("arrayifiedCompetitorsList:",arrayifiedCompetitorsList)

    // var donut = JSON.parse('["c1":{"rating":1600,"wins":0,"losses":0},"c2":{"rating":1600;"wins":0,"losses":0}]')
    // console.log(donut)

    // '"c1":{"rating":1600;"wins":0;"losses":0},"c2":{"rating";1600,"wins";0"losses";0}'
    // donut.split(',') ==> outputs
    // donutSplit = [
    //   '"c1":{"rating":1600;"wins":0;"losses":0}',
    //   '"c2":{"rating":1600;"wins":0;"losses":0}'
    // ]

    //doesn't work either.

    //BUT THIS DOES WORK!

    // var what = '{"c1":{"rating":1600,"wins":0,"losses":0}}'

    // JSON.parse(what)

    var competitorsName = Object.keys(object)
    var numberOfCompetitors = competitorsName.length

    // console.log(_.values(object))
    // console.log("competitorsName:",competitorsName)
    // console.log("numberOfCompetitors:",numberOfCompetitors)

    for ( var k = 1; k <= numberOfCompetitors; k++) {

      //_.values(obj) might be the way

      // bullPen.push(object[k])

    }

  }

  bullPenCreator(allCompetitorsObj)

}

tournamentRegistrator(numberOfRequiredRounds)

var tournamentCoordinator = function(array){

  // console.log("tournamentCoordinator's array:",array)
  // console.log("arrayOfCompetitors.length:",array.length)

  for ( var i = 0; i < array.length; i++ ) {

    var firstCompetitor        = null
    var secondCompetitor       = null
    var nameOfFirstCompetitor  = null
    var nameOfSecondCompetitor = null
    var firstCompetitorRating  = null
    var secondCompetitorRating = null

    var recordWinsForFirstCompetitor    = 0
    var recordWinsForSecondCompetitor   = 0
    var recordLossesForFirstCompetitor  = 0
    var recordLossesForSecondCompetitor = 0

  // console.log("firstCompetitor:",firstCompetitor)
  // console.log("Name of First Competitor:",nameOfFirstCompetitor)
  // console.log("secondCompetitor:",secondCompetitor)
  // console.log("Name of Second Competitor:",nameOfSecondCompetitor)
  // console.log("firstCompetitorRating:",firstCompetitorRating)
  // console.log("secondCompetitorRating:",secondCompetitorRating)

    var matPopulator = function(array){
      theCompetitionMat.push(array.shift())
      theCompetitionMat.push(array.shift())
    }
    var variableAssigner = function(array){

      firstCompetitor  = array[0]
      secondCompetitor = array[1]
      nameOfFirstCompetitor  = Object.keys(firstCompetitor)[0]
      nameOfSecondCompetitor = Object.keys(secondCompetitor)[0]

      firstCompetitorRating  = firstCompetitor[nameOfFirstCompetitor]['rating']
      secondCompetitorRating = secondCompetitor[nameOfSecondCompetitor]['rating']

      recordWinsForFirstCompetitor    = firstCompetitor[nameOfFirstCompetitor]['wins']
      recordLossesForFirstCompetitor  = firstCompetitor[nameOfFirstCompetitor]['losses']
      recordWinsForSecondCompetitor   = secondCompetitor[nameOfSecondCompetitor]['wins']
      recordLossesForSecondCompetitor = secondCompetitor[nameOfSecondCompetitor]['losses']

      // console.log("firstCompetitor[name]['wins']:",firstCompetitor[nameOfFirstCompetitor]['wins'])
      // console.log("Name of First Competitor:",nameOfFirstCompetitor)
      // console.log("secondCompetitor[name]:",secondCompetitor[nameOfSecondCompetitor])
      // console.log("Name of Second Competitor:",nameOfSecondCompetitor)
      // console.log("firstCompetitorRating:",firstCompetitorRating)
      // console.log("secondCompetitorRating:",secondCompetitorRating)

    }
    var probabilityCalculator = function(array){

      // TODO: rename these next six variables!

      // var recordWinsForA    = firstCompetitor[nameOfFirstCompetitor]['wins']
      // var recordWinsForB    = secondCompetitor[nameOfSecondCompetitor]['wins']
      // var recordLossesForA  = firstCompetitor[nameOfFirstCompetitor]['losses']
      // var recordLossesForB  = secondCompetitor[nameOfSecondCompetitor]['losses']

      firstCompetitorsProbabilityOfVictory = 1 / (1 + Math.pow(10, ((secondCompetitorRating - firstCompetitorRating) / 400)))
      secondCompetitorsProbabilityOfVictory = 1 / (1 + Math.pow(10, ((firstCompetitorRating - secondCompetitorRating) / 400)))

      // competitionMatOdds.push(probabilityOfVictoryForA)
      // competitionMatOdds.push(probabilityOfVictoryForB)

      // console.log("firstCompetitorsProbabilityOfVictory:", firstCompetitorsProbabilityOfVictory)
      // console.log("secondCompetitorsProbabilityOfVictory:", secondCompetitorsProbabilityOfVictory)
      // console.log("recordWinsForA:",recordWinsForA)
      // console.log("recordWinsForB:",recordWinsForB)
      // console.log("recordLossesForA:",recordLossesForA)
      // console.log("recordLossesForB:",recordLossesForB)
      // console.log("theCompetitionFloor:",array)
    }
    var referee = function(array,probability){

      var randomNumber = Math.random()

      if ( probability > randomNumber ) {

        // console.log("first person wins!")
        // console.log("second person loses!")

        // console.log("firstCompetitor[nameOfFirstCompetitor]['wins']:",firstCompetitor[nameOfFirstCompetitor]['wins'])
        // console.log("secondCompetitor[nameOfSecondCompetitor]['wins']:"secondCompetitor[nameOfSecondCompetitor]['wins'])

        if ( recordWinsForFirstCompetitor === 0 ) {

          // console.log("the first competitor has no wins!")
          firstCompetitor[nameOfFirstCompetitor]['wins']++
          secondCompetitor[nameOfSecondCompetitor]['losses']++

        } else {

          // console.log("the first competitor has no wins!")
          firstCompetitor[nameOfFirstCompetitor]['wins']++
          secondCompetitor[nameOfSecondCompetitor]['losses']++

        }

        // recordWinsForFirstCompetitor++
        // recordLossesForSecondCompetitor++

        // firstCompetitor[nameOfFirstCompetitor]['wins']     = recordWinsForFirstCompetitor
        // console.log("*****firstCompetitor:",firstCompetitor)
        // console.log("*****firstCompetitor[nameOfFirstCompetitor]:",firstCompetitor[nameOfFirstCompetitor])

        // console.log("firstCompetitor[nameOfFirstCompetitor]['wins']:",firstCompetitor[nameOfFirstCompetitor]['wins'])
        // secondCompetitor[nameOfSecondCompetitor]['losses'] = recordLossesForSecondCompetitor
        // console.log("secondCompetitor[nameOfFirstCompetitor]['losses']:",secondCompetitor[nameOfFirstCompetitor]['losses'])

      } else {

        // console.log("first person loses!")
        // console.log("second person wins!")

        if ( recordWinsForSecondCompetitor === 0 ) {

          // console.log("the second competitor has no wins!")
          firstCompetitor[nameOfFirstCompetitor]['losses']++
          secondCompetitor[nameOfSecondCompetitor]['wins']++

        } else {
          // console.log("the second competitor has some wins!")

          firstCompetitor[nameOfFirstCompetitor]['losses']++
          secondCompetitor[nameOfSecondCompetitor]['wins']++

        }

        // recordLossesForFirstCompetitor++
        // recordWinsForSecondCompetitor++

        // console.log("recordWinsForA:",recordWinsForA)
        // console.log("recordWinsForB:",recordWinsForB)

        // firstCompetitor[nameOfFirstCompetitor]['losses'] = recordLossesForFirstCompetitor
        // console.log("*****firstCompetitor:",firstCompetitor)

        // console.log("*****firstCompetitor[nameOfFirstCompetitor]:",firstCompetitor[nameOfFirstCompetitor])
        // console.log("*****firstCompetitor[nameOfFirstCompetitor]['losses']:",firstCompetitor[nameOfFirstCompetitor]['losses'])

        // secondCompetitor[nameOfSecondCompetitor]['wins'] = recordWinsForSecondCompetitor
        // console.log("secondCompetitor[nameOfFirstCompetitor]['wins']:",secondCompetitor[nameOfFirstCompetitor]['wins'])

      }
    }
    var ratingsAdjuster = function() {

      // console.log("after referee() theCompetitionMat:",theCompetitionMat)

      // console.log("ratingsAdjuster's array:",array)

      // console.log("firstCompetitorRating:",firstCompetitorRating)
      // console.log("secondCompetitorRating:",secondCompetitorRating)

      var rawNewRatingForFirst = firstCompetitorRating + k*(firstCompetitor[nameOfFirstCompetitor]['wins'] - (firstCompetitorsProbabilityOfVictory*n))
      var rawNewRatingForSecond = secondCompetitorRating + k*(secondCompetitor[nameOfSecondCompetitor]['wins'] - (secondCompetitorsProbabilityOfVictory*n))

      // console.log("rawNewRatingForFirst:",rawNewRatingForFirst)
      // console.log("rawNewRatingForSecond:",rawNewRatingForSecond)

      var newRatingForFirst = Math.round(rawNewRatingForFirst)
      var newRatingForSecond = Math.round(rawNewRatingForSecond)

      // console.log("newRatingForFirst:",newRatingForFirst)
      // console.log("newRatingForSecond:",newRatingForSecond)

      firstCompetitor[nameOfFirstCompetitor]['rating']   = newRatingForFirst
      secondCompetitor[nameOfSecondCompetitor]['rating'] = newRatingForSecond

      // console.log("after everything --> ratingsAdjuster's array:",array)

      //TODO: this needs to be refactored to handle two newRatings simultaneously
      // if (newRating === competitorRating && competitorRating < rawNewRating ) {
      //
      //   competitor[competitorStats[0]] = newRating+1
      //
      // } else if ( newRating === competitorRating && competitorRating > rawNewRating ) {
      //
      //   competitor[competitorStats[0]] = newRating-1
      //
      // } else {
      //
      //   competitor[competitorStats[0]] = newRating
      //
      // }
    }
    var matEvacuator = function(array){
      // console.log("this should be the competitionFloor!:",array)

      if ( firstCompetitor[nameOfFirstCompetitor]['losses'] ) {

        // console.log("the first competitor lost!")
        winnersBracket.push(array.pop())
        losersBracket.push(array.pop())
        // console.log("winnersBracket:",winnersBracket)
        // console.log("losersBracket:",losersBracket)

      } else {

        // console.log("the second person lost!")
        losersBracket.push(array.pop())
        winnersBracket.push(array.pop())

        // console.log("losersBracket:",losersBracket)
        // console.log("winnersBracket:",winnersBracket)

        // console.log("array after populating losers and winners brackets:",array)
        // console.log("arrayOfCompetitors:",arrayOfCompetitors)

      }
    }

    matPopulator(array)
    variableAssigner(theCompetitionMat)
    probabilityCalculator(theCompetitionMat)
    referee(theCompetitionMat, firstCompetitorsProbabilityOfVictory)
    ratingsAdjuster()
    matEvacuator(theCompetitionMat)

  }

  // console.log("arrayOfCompetitors:",arrayOfCompetitors)
  // console.log("winnersBracket:",winnersBracket)
  // console.log("losersBracket:",losersBracket)

  if ( array.length === 1 ) {
    console.log("YOU ARE THE WINNER!:",array[0])
    console.log("Loser's Bracket:",losersBracket)
  } else if ( array.length === 0 ) {
    console.log("you ran out of competitors!")
    tournamentCoordinator(winnersBracket)
  } else if ( array.length ) {
    console.log("hello sailor!  We still have fights left!")
    tournamentCoordinator(array)
  }

}

tournamentCoordinator(outputArr)
<commit_msg>BullPenCreator() removed<commit_after>/**
 * Created by justin.baize on 6/16/16.
 */

'use strict'
var fs = require('fs');
var _  = require('lodash');

var theCompetitionMat  = []
var winnersBracket     = []
var losersBracket      = []
var firstCompetitorsProbabilityOfVictory  = 0
var secondCompetitorsProbabilityOfVictory = 0
var numberOfRequiredRounds = 4

var k = 16
var n = 1

/**
 * @name matPopulator
 * @description - Takes two competitors from arrayOfCompetitors and
 *                puts them into theCompetitionMat array.
 * @param arrayOfCompetitors
 **/

var outputArr = []

var tournamentRegistrator = function(number) {

  var allCompetitorsObj = {}
  var squared = number * number
  var prototypeCompetitor = {rating: 1600, wins: 0, losses: 0}

  //this will output an object with
  //competitors === squared
  //outputObj: {
  //             c(n): { rating: 1600, wins: 0, losses: 0 },
  //             c(n+1): { rating: 1600, wins: 0, losses: 0 },
  //             c(n+2): { rating: 1600, wins: 0, losses: 0 },
  //           }
  var competitorCreator = function (squared) {
    var tempArr = []
    var tempArr2 = []

    for (var j = 1; j <= squared; j++) {
      var yourNumber = j.toString()
      var name = "c" + yourNumber
      var competitorAssembler = '{"c' + yourNumber +'":{"rating":1600,"wins":0,"losses":0}}'

      // console.log("competitorAssembler:",competitorAssembler)
      // console.log("typeof competitorAssembler:",typeof competitorAssembler)

      // console.log("JSON.parse(competitorAssembler):",JSON.parse(competitorAssembler))
      // console.log("typeof JSON.parse(competitorAssembler):",typeof JSON.parse(competitorAssembler))

      // this is the goal
      // '{"c1":{"rating":1600,"wins":0,"losses":0}}'

      outputArr.push(JSON.parse(competitorAssembler))
      // tempArr2.push(prototypeCompetitor)
    }
    console.log("outputArr:",outputArr)
    // allCompetitorsObj = _.zipObject(tempArr, tempArr2)
  }

  competitorCreator(squared)

}

tournamentRegistrator(numberOfRequiredRounds)

var tournamentCoordinator = function(array){

  // console.log("tournamentCoordinator's array:",array)
  // console.log("arrayOfCompetitors.length:",array.length)

  for ( var i = 0; i < array.length; i++ ) {

    var firstCompetitor        = null
    var secondCompetitor       = null
    var nameOfFirstCompetitor  = null
    var nameOfSecondCompetitor = null
    var firstCompetitorRating  = null
    var secondCompetitorRating = null

    var recordWinsForFirstCompetitor    = 0
    var recordWinsForSecondCompetitor   = 0
    var recordLossesForFirstCompetitor  = 0
    var recordLossesForSecondCompetitor = 0

  // console.log("firstCompetitor:",firstCompetitor)
  // console.log("Name of First Competitor:",nameOfFirstCompetitor)
  // console.log("secondCompetitor:",secondCompetitor)
  // console.log("Name of Second Competitor:",nameOfSecondCompetitor)
  // console.log("firstCompetitorRating:",firstCompetitorRating)
  // console.log("secondCompetitorRating:",secondCompetitorRating)

    var matPopulator = function(array){
      theCompetitionMat.push(array.shift())
      theCompetitionMat.push(array.shift())
    }
    var variableAssigner = function(array){

      firstCompetitor  = array[0]
      secondCompetitor = array[1]
      nameOfFirstCompetitor  = Object.keys(firstCompetitor)[0]
      nameOfSecondCompetitor = Object.keys(secondCompetitor)[0]

      firstCompetitorRating  = firstCompetitor[nameOfFirstCompetitor]['rating']
      secondCompetitorRating = secondCompetitor[nameOfSecondCompetitor]['rating']

      recordWinsForFirstCompetitor    = firstCompetitor[nameOfFirstCompetitor]['wins']
      recordLossesForFirstCompetitor  = firstCompetitor[nameOfFirstCompetitor]['losses']
      recordWinsForSecondCompetitor   = secondCompetitor[nameOfSecondCompetitor]['wins']
      recordLossesForSecondCompetitor = secondCompetitor[nameOfSecondCompetitor]['losses']

      // console.log("firstCompetitor[name]['wins']:",firstCompetitor[nameOfFirstCompetitor]['wins'])
      // console.log("Name of First Competitor:",nameOfFirstCompetitor)
      // console.log("secondCompetitor[name]:",secondCompetitor[nameOfSecondCompetitor])
      // console.log("Name of Second Competitor:",nameOfSecondCompetitor)
      // console.log("firstCompetitorRating:",firstCompetitorRating)
      // console.log("secondCompetitorRating:",secondCompetitorRating)

    }
    var probabilityCalculator = function(array){

      // TODO: rename these next six variables!

      // var recordWinsForA    = firstCompetitor[nameOfFirstCompetitor]['wins']
      // var recordWinsForB    = secondCompetitor[nameOfSecondCompetitor]['wins']
      // var recordLossesForA  = firstCompetitor[nameOfFirstCompetitor]['losses']
      // var recordLossesForB  = secondCompetitor[nameOfSecondCompetitor]['losses']

      firstCompetitorsProbabilityOfVictory = 1 / (1 + Math.pow(10, ((secondCompetitorRating - firstCompetitorRating) / 400)))
      secondCompetitorsProbabilityOfVictory = 1 / (1 + Math.pow(10, ((firstCompetitorRating - secondCompetitorRating) / 400)))

      // competitionMatOdds.push(probabilityOfVictoryForA)
      // competitionMatOdds.push(probabilityOfVictoryForB)

      // console.log("firstCompetitorsProbabilityOfVictory:", firstCompetitorsProbabilityOfVictory)
      // console.log("secondCompetitorsProbabilityOfVictory:", secondCompetitorsProbabilityOfVictory)
      // console.log("recordWinsForA:",recordWinsForA)
      // console.log("recordWinsForB:",recordWinsForB)
      // console.log("recordLossesForA:",recordLossesForA)
      // console.log("recordLossesForB:",recordLossesForB)
      // console.log("theCompetitionFloor:",array)
    }
    var referee = function(array,probability){

      var randomNumber = Math.random()

      if ( probability > randomNumber ) {

        // console.log("first person wins!")
        // console.log("second person loses!")

        // console.log("firstCompetitor[nameOfFirstCompetitor]['wins']:",firstCompetitor[nameOfFirstCompetitor]['wins'])
        // console.log("secondCompetitor[nameOfSecondCompetitor]['wins']:"secondCompetitor[nameOfSecondCompetitor]['wins'])

        if ( recordWinsForFirstCompetitor === 0 ) {

          // console.log("the first competitor has no wins!")
          firstCompetitor[nameOfFirstCompetitor]['wins']++
          secondCompetitor[nameOfSecondCompetitor]['losses']++

        } else {

          // console.log("the first competitor has no wins!")
          firstCompetitor[nameOfFirstCompetitor]['wins']++
          secondCompetitor[nameOfSecondCompetitor]['losses']++

        }

        // recordWinsForFirstCompetitor++
        // recordLossesForSecondCompetitor++

        // firstCompetitor[nameOfFirstCompetitor]['wins']     = recordWinsForFirstCompetitor
        // console.log("*****firstCompetitor:",firstCompetitor)
        // console.log("*****firstCompetitor[nameOfFirstCompetitor]:",firstCompetitor[nameOfFirstCompetitor])

        // console.log("firstCompetitor[nameOfFirstCompetitor]['wins']:",firstCompetitor[nameOfFirstCompetitor]['wins'])
        // secondCompetitor[nameOfSecondCompetitor]['losses'] = recordLossesForSecondCompetitor
        // console.log("secondCompetitor[nameOfFirstCompetitor]['losses']:",secondCompetitor[nameOfFirstCompetitor]['losses'])

      } else {

        // console.log("first person loses!")
        // console.log("second person wins!")

        if ( recordWinsForSecondCompetitor === 0 ) {

          // console.log("the second competitor has no wins!")
          firstCompetitor[nameOfFirstCompetitor]['losses']++
          secondCompetitor[nameOfSecondCompetitor]['wins']++

        } else {
          // console.log("the second competitor has some wins!")

          firstCompetitor[nameOfFirstCompetitor]['losses']++
          secondCompetitor[nameOfSecondCompetitor]['wins']++

        }

        // recordLossesForFirstCompetitor++
        // recordWinsForSecondCompetitor++

        // console.log("recordWinsForA:",recordWinsForA)
        // console.log("recordWinsForB:",recordWinsForB)

        // firstCompetitor[nameOfFirstCompetitor]['losses'] = recordLossesForFirstCompetitor
        // console.log("*****firstCompetitor:",firstCompetitor)

        // console.log("*****firstCompetitor[nameOfFirstCompetitor]:",firstCompetitor[nameOfFirstCompetitor])
        // console.log("*****firstCompetitor[nameOfFirstCompetitor]['losses']:",firstCompetitor[nameOfFirstCompetitor]['losses'])

        // secondCompetitor[nameOfSecondCompetitor]['wins'] = recordWinsForSecondCompetitor
        // console.log("secondCompetitor[nameOfFirstCompetitor]['wins']:",secondCompetitor[nameOfFirstCompetitor]['wins'])

      }
    }
    var ratingsAdjuster = function() {

      // console.log("after referee() theCompetitionMat:",theCompetitionMat)

      // console.log("ratingsAdjuster's array:",array)

      // console.log("firstCompetitorRating:",firstCompetitorRating)
      // console.log("secondCompetitorRating:",secondCompetitorRating)

      var rawNewRatingForFirst = firstCompetitorRating + k*(firstCompetitor[nameOfFirstCompetitor]['wins'] - (firstCompetitorsProbabilityOfVictory*n))
      var rawNewRatingForSecond = secondCompetitorRating + k*(secondCompetitor[nameOfSecondCompetitor]['wins'] - (secondCompetitorsProbabilityOfVictory*n))

      // console.log("rawNewRatingForFirst:",rawNewRatingForFirst)
      // console.log("rawNewRatingForSecond:",rawNewRatingForSecond)

      var newRatingForFirst = Math.round(rawNewRatingForFirst)
      var newRatingForSecond = Math.round(rawNewRatingForSecond)

      // console.log("newRatingForFirst:",newRatingForFirst)
      // console.log("newRatingForSecond:",newRatingForSecond)

      firstCompetitor[nameOfFirstCompetitor]['rating']   = newRatingForFirst
      secondCompetitor[nameOfSecondCompetitor]['rating'] = newRatingForSecond

      // console.log("after everything --> ratingsAdjuster's array:",array)

      //TODO: this needs to be refactored to handle two newRatings simultaneously
      // if (newRating === competitorRating && competitorRating < rawNewRating ) {
      //
      //   competitor[competitorStats[0]] = newRating+1
      //
      // } else if ( newRating === competitorRating && competitorRating > rawNewRating ) {
      //
      //   competitor[competitorStats[0]] = newRating-1
      //
      // } else {
      //
      //   competitor[competitorStats[0]] = newRating
      //
      // }
    }
    var matEvacuator = function(array){
      // console.log("this should be the competitionFloor!:",array)

      if ( firstCompetitor[nameOfFirstCompetitor]['losses'] ) {

        // console.log("the first competitor lost!")
        winnersBracket.push(array.pop())
        losersBracket.push(array.pop())
        // console.log("winnersBracket:",winnersBracket)
        // console.log("losersBracket:",losersBracket)

      } else {

        // console.log("the second person lost!")
        losersBracket.push(array.pop())
        winnersBracket.push(array.pop())

        // console.log("losersBracket:",losersBracket)
        // console.log("winnersBracket:",winnersBracket)

        // console.log("array after populating losers and winners brackets:",array)
        // console.log("arrayOfCompetitors:",arrayOfCompetitors)

      }
    }

    matPopulator(array)
    variableAssigner(theCompetitionMat)
    probabilityCalculator(theCompetitionMat)
    referee(theCompetitionMat, firstCompetitorsProbabilityOfVictory)
    ratingsAdjuster()
    matEvacuator(theCompetitionMat)

  }

  // console.log("arrayOfCompetitors:",arrayOfCompetitors)
  // console.log("winnersBracket:",winnersBracket)
  // console.log("losersBracket:",losersBracket)

  if ( array.length === 1 ) {
    console.log("YOU ARE THE WINNER!:",array[0])
    console.log("Loser's Bracket:",losersBracket)
  } else if ( array.length === 0 ) {
    console.log("you ran out of competitors!")
    tournamentCoordinator(winnersBracket)
  } else if ( array.length ) {
    console.log("hello sailor!  We still have fights left!")
    tournamentCoordinator(array)
  }

}

tournamentCoordinator(outputArr)
<|endoftext|>


<commit_before>describe('Clear vars sandbox', function () {
    var _ = require('lodash'),
        testrun;

    before(function (done) {
        this.run({
            environment: {values: [{key: 'e', value: '2'}]},
            globals: {values: [{key: 'g', value: '3'}]},
            collection: {
                item: [{
                    event: [{
                        listen: 'test',
                        script: {
                            exec: [
                                'var data = JSON.parse(responseBody);',
                                'tests[\'Variable substitution from env\'] = (data.args.a===\'2\');',
                                'tests[\'Variable substitution from global\'] = (data.args.b===\'3\');',
                                'postman.clearEnvironmentVariables();',
                                'postman.clearGlobalVariables();'
                            ]
                        }
                    }],
                    request: {
                        url: 'https://postman-echo.com/get?a={{e}}&b={{g}}',
                        method: 'GET'
                    }
                }, {
                    event: [{
                        listen: 'test',
                        script: {
                            exec: [
                                'var data = JSON.parse(responseBody);',
                                // eslint-disable-next-line max-len
                                'tests[\'Variable substitution from env not working after clearing\'] = (data.args.a===\'{{e}}\');',
                                // eslint-disable-next-line max-len
                                'tests[\'Variable substitution from global not working after clearing\'] = (data.args.b===\'{{g}}\');',
                                'postman.setEnvironmentVariable(\'e\', \'2\');',
                                'postman.setGlobalVariable(\'g\',\'3\');',
                                'tests[\'Recreated vars\']=environment.e===\'2\' && globals.g===\'3\'',
                                'postman.clearEnvironmentVariable(\'e\');',
                                'postman.clearGlobalVariable(\'g\');'
                            ]
                        }
                    }],
                    request: {
                        url: 'https://postman-echo.com/get?a={{e}}&b={{g}}',
                        method: 'GET'
                    }
                }, {
                    event: [{
                        listen: 'test',
                        script: {
                            exec: [
                                'var data = JSON.parse(responseBody);',
                                // eslint-disable-next-line max-len
                                'tests[\'Variable substitution from env not working after clearing invididually\'] = (data.args.a===\'{{e}}\');',
                                // eslint-disable-next-line max-len
                                'tests[\'Variable substitution from global not working after clearing invididually\'] = (data.args.b===\'{{g}}\');'
                            ]
                        }
                    }],
                    request: {
                        url: 'https://postman-echo.com/get?a={{e}}&b={{g}}',
                        method: 'GET'
                    }
                }]
            }
        }, function (err, results) {
            testrun = results;
            done(err);
        });
    });

    describe('test scripts', function () {
        it('should have run thrice', function () {
            expect(testrun).be.ok();
            expect(testrun.test.calledThrice).be.ok();
        });

        it('should correctly clear environments and globals in the test run 1', function () {
            var first = testrun.test.getCall(0);

            expect(first.args[0]).to.be(null);
            expect(_.invoke(first.args[2], '0.result.globals.values.all')).to.eql([]);
            expect(_.invoke(first.args[2], '0.result.environment.values.all')).to.eql([]);
        });

        it('should correctly clear environments and globals in the test run 2', function () {
            var second = testrun.test.getCall(1);

            expect(second.args[0]).to.be(null);
            expect(_.invoke(second.args[2], '0.result.globals.values.all')).to.eql([]);
            expect(_.invoke(second.args[2], '0.result.environment.values.all')).to.eql([]);
        });

        it('should correctly clear environments and globals in the test run 3', function () {
            var third = testrun.test.getCall(2);

            expect(third.args[0]).to.be(null);
            expect(_.invoke(third.args[2], '0.result.globals.values.all')).to.eql([]);
            expect(_.invoke(third.args[2], '0.result.environment.values.all')).to.eql([]);
        });
    });

    it('must have completed the run', function () {
        expect(testrun).be.ok();
        expect(testrun.done.calledOnce).be.ok();
        expect(testrun.done.getCall(0).args[0]).to.be(null);
        expect(testrun.start.calledOnce).be.ok();
    });
});
<commit_msg>Update integration/sanity/clear-vars-sandbox tests to chai<commit_after>var expect = require('chai').expect;

describe('Clear vars sandbox', function () {
    var _ = require('lodash'),
        testrun;

    before(function (done) {
        this.run({
            environment: {values: [{key: 'e', value: '2'}]},
            globals: {values: [{key: 'g', value: '3'}]},
            collection: {
                item: [{
                    event: [{
                        listen: 'test',
                        script: {
                            exec: [
                                'var data = JSON.parse(responseBody);',
                                'tests[\'Variable substitution from env\'] = (data.args.a===\'2\');',
                                'tests[\'Variable substitution from global\'] = (data.args.b===\'3\');',
                                'postman.clearEnvironmentVariables();',
                                'postman.clearGlobalVariables();'
                            ]
                        }
                    }],
                    request: {
                        url: 'https://postman-echo.com/get?a={{e}}&b={{g}}',
                        method: 'GET'
                    }
                }, {
                    event: [{
                        listen: 'test',
                        script: {
                            exec: [
                                'var data = JSON.parse(responseBody);',
                                // eslint-disable-next-line max-len
                                'tests[\'Variable substitution from env not working after clearing\'] = (data.args.a===\'{{e}}\');',
                                // eslint-disable-next-line max-len
                                'tests[\'Variable substitution from global not working after clearing\'] = (data.args.b===\'{{g}}\');',
                                'postman.setEnvironmentVariable(\'e\', \'2\');',
                                'postman.setGlobalVariable(\'g\',\'3\');',
                                'tests[\'Recreated vars\']=environment.e===\'2\' && globals.g===\'3\'',
                                'postman.clearEnvironmentVariable(\'e\');',
                                'postman.clearGlobalVariable(\'g\');'
                            ]
                        }
                    }],
                    request: {
                        url: 'https://postman-echo.com/get?a={{e}}&b={{g}}',
                        method: 'GET'
                    }
                }, {
                    event: [{
                        listen: 'test',
                        script: {
                            exec: [
                                'var data = JSON.parse(responseBody);',
                                // eslint-disable-next-line max-len
                                'tests[\'Variable substitution from env not working after clearing invididually\'] = (data.args.a===\'{{e}}\');',
                                // eslint-disable-next-line max-len
                                'tests[\'Variable substitution from global not working after clearing invididually\'] = (data.args.b===\'{{g}}\');'
                            ]
                        }
                    }],
                    request: {
                        url: 'https://postman-echo.com/get?a={{e}}&b={{g}}',
                        method: 'GET'
                    }
                }]
            }
        }, function (err, results) {
            testrun = results;
            done(err);
        });
    });

    describe('test scripts', function () {
        it('should have run thrice', function () {
            expect(testrun).to.be.ok;
            expect(testrun).to.nested.include({
                'test.calledThrice': true
            });
        });

        it('should correctly clear environments and globals in the test run 1', function () {
            var first = testrun.test.getCall(0);

            expect(first.args[0]).to.be.null;
            expect(_.invoke(first.args[2], '0.result.globals.values.all')).to.eql([]);
            expect(_.invoke(first.args[2], '0.result.environment.values.all')).to.eql([]);
        });

        it('should correctly clear environments and globals in the test run 2', function () {
            var second = testrun.test.getCall(1);

            expect(second.args[0]).to.be.null;
            expect(_.invoke(second.args[2], '0.result.globals.values.all')).to.eql([]);
            expect(_.invoke(second.args[2], '0.result.environment.values.all')).to.eql([]);
        });

        it('should correctly clear environments and globals in the test run 3', function () {
            var third = testrun.test.getCall(2);

            expect(third.args[0]).to.be.null;
            expect(_.invoke(third.args[2], '0.result.globals.values.all')).to.eql([]);
            expect(_.invoke(third.args[2], '0.result.environment.values.all')).to.eql([]);
        });
    });

    it('should have completed the run', function () {
        expect(testrun).to.be.ok;
        expect(testrun.done.getCall(0).args[0]).to.be.null;
        expect(testrun).to.nested.include({
            'done.calledOnce': true,
            'start.calledOnce': true
        });
    });
});
<|endoftext|>


<commit_before>// Copyright (C) 2016 The Android Open Source Project
//
// Licensed 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.
(function() {
  'use strict';

  Polymer({
    is: 'gr-diff-highlight',

    properties: {
      comments: Object,
      loggedIn: Boolean,
      _cachedDiffBuilder: Object,
      isAttached: Boolean,
    },

    listeners: {
      'comment-mouse-out': '_handleCommentMouseOut',
      'comment-mouse-over': '_handleCommentMouseOver',
      'create-comment': '_createComment',
    },

    observers: [
      '_enableSelectionObserver(loggedIn, isAttached)',
    ],

    get diffBuilder() {
      if (!this._cachedDiffBuilder) {
        this._cachedDiffBuilder =
            Polymer.dom(this).querySelector('gr-diff-builder');
      }
      return this._cachedDiffBuilder;
    },

    _enableSelectionObserver(loggedIn, isAttached) {
      if (loggedIn && isAttached) {
        this.listen(document, 'selectionchange', '_handleSelectionChange');
      } else {
        this.unlisten(document, 'selectionchange', '_handleSelectionChange');
      }
    },

    isRangeSelected() {
      return !!this.$$('gr-selection-action-box');
    },

    _handleSelectionChange() {
      // Can't use up or down events to handle selection started and/or ended in
      // in comment threads or outside of diff.
      // Debounce removeActionBox to give it a chance to react to click/tap.
      this._removeActionBoxDebounced();
      this.debounce('selectionChange', this._handleSelection, 200);
    },

    _handleCommentMouseOver(e) {
      const comment = e.detail.comment;
      if (!comment.range) { return; }
      const lineEl = this.diffBuilder.getLineElByChild(e.target);
      const side = this.diffBuilder.getSideByLineEl(lineEl);
      const index = this._indexOfComment(side, comment);
      if (index !== undefined) {
        this.set(['comments', side, index, '__hovering'], true);
      }
    },

    _handleCommentMouseOut(e) {
      const comment = e.detail.comment;
      if (!comment.range) { return; }
      const lineEl = this.diffBuilder.getLineElByChild(e.target);
      const side = this.diffBuilder.getSideByLineEl(lineEl);
      const index = this._indexOfComment(side, comment);
      if (index !== undefined) {
        this.set(['comments', side, index, '__hovering'], false);
      }
    },

    _indexOfComment(side, comment) {
      const idProp = comment.id ? 'id' : '__draftID';
      for (let i = 0; i < this.comments[side].length; i++) {
        if (comment[idProp] &&
            this.comments[side][i][idProp] === comment[idProp]) {
          return i;
        }
      }
    },

    /**
     * Get current normalized selection.
     * Merges multiple ranges, accounts for triple click, accounts for
     * syntax highligh, convert native DOM Range objects to Gerrit concepts
     * (line, side, etc).
     * @return {{
     *   start: {
     *     node: Node,
     *     side: string,
     *     line: Number,
     *     column: Number
     *   },
     *   end: {
     *     node: Node,
     *     side: string,
     *     line: Number,
     *     column: Number
     *   }
     * }}
     */
    _getNormalizedRange() {
      const selection = window.getSelection();
      const rangeCount = selection.rangeCount;
      if (rangeCount === 0) {
        return null;
      } else if (rangeCount === 1) {
        return this._normalizeRange(selection.getRangeAt(0));
      } else {
        const startRange = this._normalizeRange(selection.getRangeAt(0));
        const endRange = this._normalizeRange(
            selection.getRangeAt(rangeCount - 1));
        return {
          start: startRange.start,
          end: endRange.end,
        };
      }
    },

    /**
     * Normalize a specific DOM Range.
     */
    _normalizeRange(domRange) {
      const range = GrRangeNormalizer.normalize(domRange);
      return this._fixTripleClickSelection({
        start: this._normalizeSelectionSide(
            range.startContainer, range.startOffset),
        end: this._normalizeSelectionSide(
            range.endContainer, range.endOffset),
      }, domRange);
    },

    /**
     * Adjust triple click selection for the whole line.
     * domRange.endContainer may be one of the following:
     * 1) 0 offset at right column's line number cell, or
     * 2) 0 offset at left column's line number at the next line.
     * Case 1 means left column was triple clicked.
     * Case 2 means right column or unified view triple clicked.
     * @param {!Object} range Normalized range, ie column/line numbers
     * @param {!Range} domRange DOM Range object
     * @return {!Object} fixed normalized range
     */
    _fixTripleClickSelection(range, domRange) {
      if (!range.start) {
        // Selection outside of current diff.
        return range;
      }
      const start = range.start;
      const end = range.end;
      const endsAtOtherSideLineNum =
          domRange.endOffset === 0 &&
          domRange.endContainer.nodeName === 'TD' &&
          (domRange.endContainer.classList.contains('left') ||
              domRange.endContainer.classList.contains('right'));
      const endsOnOtherSideStart = endsAtOtherSideLineNum ||
          end &&
          end.column === 0 &&
          end.line === start.line &&
          end.side != start.side;
      if (endsOnOtherSideStart || endsAtOtherSideLineNum) {
        // Selection ends at the beginning of the next line.
        // Move the selection to the end of the previous line.
        range.end = {
          node: start.node,
          column: this._getLength(
              domRange.cloneContents().querySelector('.contentText')),
          side: start.side,
          line: start.line,
        };
      }
      return range;
    },

    /**
     * Convert DOM Range selection to concrete numbers (line, column, side).
     * Moves range end if it's not inside td.content.
     * Returns null if selection end is not valid (outside of diff).
     *
     * @param {Node} node td.content child
     * @param {number} offset offset within node
     * @return {{
     *   node: Node,
     *   side: string,
     *   line: Number,
     *   column: Number
     * }}
     */
    _normalizeSelectionSide(node, offset) {
      let column;
      if (!this.contains(node)) {
        return;
      }
      const lineEl = this.diffBuilder.getLineElByChild(node);
      if (!lineEl) {
        return;
      }
      const side = this.diffBuilder.getSideByLineEl(lineEl);
      if (!side) {
        return;
      }
      const line = this.diffBuilder.getLineNumberByChild(lineEl);
      if (!line) {
        return;
      }
      const contentText = this.diffBuilder.getContentByLineEl(lineEl);
      if (!contentText) {
        return;
      }
      const contentTd = contentText.parentElement;
      if (!contentTd.contains(node)) {
        node = contentText;
        column = 0;
      } else {
        const thread = contentTd.querySelector('gr-diff-comment-thread');
        if (thread && thread.contains(node)) {
          column = this._getLength(contentText);
          node = contentText;
        } else {
          column = this._convertOffsetToColumn(node, offset);
        }
      }

      return {
        node,
        side,
        line,
        column,
      };
    },

    _handleSelection() {
      const normalizedRange = this._getNormalizedRange();
      if (!normalizedRange) {
        return;
      }
      const domRange = window.getSelection().getRangeAt(0);
      const start = normalizedRange.start;
      if (!start) {
        return;
      }
      const end = normalizedRange.end;
      if (!end) {
        return;
      }
      if (start.side !== end.side ||
          end.line < start.line ||
          (start.line === end.line && start.column === end.column)) {
        return;
      }

      // TODO (viktard): Drop empty first and last lines from selection.

      const actionBox = document.createElement('gr-selection-action-box');
      const root = Polymer.dom(this.root);
      root.insertBefore(actionBox, root.firstElementChild);
      actionBox.range = {
        startLine: start.line,
        startChar: start.column,
        endLine: end.line,
        endChar: end.column,
      };
      actionBox.side = start.side;
      if (start.line === end.line) {
        actionBox.placeAbove(domRange);
      } else if (start.node instanceof Text) {
        actionBox.placeAbove(start.node.splitText(start.column));
        start.node.parentElement.normalize(); // Undo splitText from above.
      } else if (start.node.classList.contains('content') &&
                 start.node.firstChild) {
        actionBox.placeAbove(start.node.firstChild);
      } else {
        actionBox.placeAbove(start.node);
      }
    },

    _createComment(e) {
      this._removeActionBox();
    },

    _removeActionBoxDebounced() {
      this.debounce('removeActionBox', this._removeActionBox, 10);
    },

    _removeActionBox() {
      const actionBox = this.$$('gr-selection-action-box');
      if (actionBox) {
        Polymer.dom(this.root).removeChild(actionBox);
      }
    },

    _convertOffsetToColumn(el, offset) {
      if (el instanceof Element && el.classList.contains('content')) {
        return offset;
      }
      while (el.previousSibling ||
          !el.parentElement.classList.contains('content')) {
        if (el.previousSibling) {
          el = el.previousSibling;
          offset += this._getLength(el);
        } else {
          el = el.parentElement;
        }
      }
      return offset;
    },

    /**
     * Traverse Element from right to left, call callback for each node.
     * Stops if callback returns true.
     *
     * @param {!Node} startNode
     * @param {function(Node):boolean} callback
     * @param {Object=} opt_flags If flags.left is true, traverse left.
     */
    _traverseContentSiblings(startNode, callback, opt_flags) {
      const travelLeft = opt_flags && opt_flags.left;
      let node = startNode;
      while (node) {
        if (node instanceof Element &&
            node.tagName !== 'HL' &&
            node.tagName !== 'SPAN') {
          break;
        }
        const nextNode = travelLeft ? node.previousSibling : node.nextSibling;
        if (callback(node)) {
          break;
        }
        node = nextNode;
      }
    },

    /**
     * Get length of a node. If the node is a content node, then only give the
     * length of its .contentText child.
     *
     * @param {!Node} node
     * @return {number}
     */
    _getLength(node) {
      if (node instanceof Element && node.classList.contains('content')) {
        return this._getLength(node.querySelector('.contentText'));
      } else {
        return GrAnnotation.getLength(node);
      }
    },
  });
})();
<commit_msg>Don't crash on empty diff selection<commit_after>// Copyright (C) 2016 The Android Open Source Project
//
// Licensed 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.
(function() {
  'use strict';

  Polymer({
    is: 'gr-diff-highlight',

    properties: {
      comments: Object,
      loggedIn: Boolean,
      _cachedDiffBuilder: Object,
      isAttached: Boolean,
    },

    listeners: {
      'comment-mouse-out': '_handleCommentMouseOut',
      'comment-mouse-over': '_handleCommentMouseOver',
      'create-comment': '_createComment',
    },

    observers: [
      '_enableSelectionObserver(loggedIn, isAttached)',
    ],

    get diffBuilder() {
      if (!this._cachedDiffBuilder) {
        this._cachedDiffBuilder =
            Polymer.dom(this).querySelector('gr-diff-builder');
      }
      return this._cachedDiffBuilder;
    },

    _enableSelectionObserver(loggedIn, isAttached) {
      if (loggedIn && isAttached) {
        this.listen(document, 'selectionchange', '_handleSelectionChange');
      } else {
        this.unlisten(document, 'selectionchange', '_handleSelectionChange');
      }
    },

    isRangeSelected() {
      return !!this.$$('gr-selection-action-box');
    },

    _handleSelectionChange() {
      // Can't use up or down events to handle selection started and/or ended in
      // in comment threads or outside of diff.
      // Debounce removeActionBox to give it a chance to react to click/tap.
      this._removeActionBoxDebounced();
      this.debounce('selectionChange', this._handleSelection, 200);
    },

    _handleCommentMouseOver(e) {
      const comment = e.detail.comment;
      if (!comment.range) { return; }
      const lineEl = this.diffBuilder.getLineElByChild(e.target);
      const side = this.diffBuilder.getSideByLineEl(lineEl);
      const index = this._indexOfComment(side, comment);
      if (index !== undefined) {
        this.set(['comments', side, index, '__hovering'], true);
      }
    },

    _handleCommentMouseOut(e) {
      const comment = e.detail.comment;
      if (!comment.range) { return; }
      const lineEl = this.diffBuilder.getLineElByChild(e.target);
      const side = this.diffBuilder.getSideByLineEl(lineEl);
      const index = this._indexOfComment(side, comment);
      if (index !== undefined) {
        this.set(['comments', side, index, '__hovering'], false);
      }
    },

    _indexOfComment(side, comment) {
      const idProp = comment.id ? 'id' : '__draftID';
      for (let i = 0; i < this.comments[side].length; i++) {
        if (comment[idProp] &&
            this.comments[side][i][idProp] === comment[idProp]) {
          return i;
        }
      }
    },

    /**
     * Get current normalized selection.
     * Merges multiple ranges, accounts for triple click, accounts for
     * syntax highligh, convert native DOM Range objects to Gerrit concepts
     * (line, side, etc).
     * @return {{
     *   start: {
     *     node: Node,
     *     side: string,
     *     line: Number,
     *     column: Number
     *   },
     *   end: {
     *     node: Node,
     *     side: string,
     *     line: Number,
     *     column: Number
     *   }
     * }}
     */
    _getNormalizedRange() {
      const selection = window.getSelection();
      const rangeCount = selection.rangeCount;
      if (rangeCount === 0) {
        return null;
      } else if (rangeCount === 1) {
        return this._normalizeRange(selection.getRangeAt(0));
      } else {
        const startRange = this._normalizeRange(selection.getRangeAt(0));
        const endRange = this._normalizeRange(
            selection.getRangeAt(rangeCount - 1));
        return {
          start: startRange.start,
          end: endRange.end,
        };
      }
    },

    /**
     * Normalize a specific DOM Range.
     */
    _normalizeRange(domRange) {
      const range = GrRangeNormalizer.normalize(domRange);
      return this._fixTripleClickSelection({
        start: this._normalizeSelectionSide(
            range.startContainer, range.startOffset),
        end: this._normalizeSelectionSide(
            range.endContainer, range.endOffset),
      }, domRange);
    },

    /**
     * Adjust triple click selection for the whole line.
     * domRange.endContainer may be one of the following:
     * 1) 0 offset at right column's line number cell, or
     * 2) 0 offset at left column's line number at the next line.
     * Case 1 means left column was triple clicked.
     * Case 2 means right column or unified view triple clicked.
     * @param {!Object} range Normalized range, ie column/line numbers
     * @param {!Range} domRange DOM Range object
     * @return {!Object} fixed normalized range
     */
    _fixTripleClickSelection(range, domRange) {
      if (!range.start) {
        // Selection outside of current diff.
        return range;
      }
      const start = range.start;
      const end = range.end;
      const endsAtOtherSideLineNum =
          domRange.endOffset === 0 &&
          domRange.endContainer.nodeName === 'TD' &&
          (domRange.endContainer.classList.contains('left') ||
              domRange.endContainer.classList.contains('right'));
      const endsOnOtherSideStart = endsAtOtherSideLineNum ||
          end &&
          end.column === 0 &&
          end.line === start.line &&
          end.side != start.side;
      const content = domRange.cloneContents().querySelector('.contentText');
      const lineLength = content && this._getLength(content) || 0;
      if (lineLength && endsOnOtherSideStart || endsAtOtherSideLineNum) {
        // Selection ends at the beginning of the next line.
        // Move the selection to the end of the previous line.
        range.end = {
          node: start.node,
          column: lineLength,
          side: start.side,
          line: start.line,
        };
      }
      return range;
    },

    /**
     * Convert DOM Range selection to concrete numbers (line, column, side).
     * Moves range end if it's not inside td.content.
     * Returns null if selection end is not valid (outside of diff).
     *
     * @param {Node} node td.content child
     * @param {number} offset offset within node
     * @return {{
     *   node: Node,
     *   side: string,
     *   line: Number,
     *   column: Number
     * }}
     */
    _normalizeSelectionSide(node, offset) {
      let column;
      if (!this.contains(node)) {
        return;
      }
      const lineEl = this.diffBuilder.getLineElByChild(node);
      if (!lineEl) {
        return;
      }
      const side = this.diffBuilder.getSideByLineEl(lineEl);
      if (!side) {
        return;
      }
      const line = this.diffBuilder.getLineNumberByChild(lineEl);
      if (!line) {
        return;
      }
      const contentText = this.diffBuilder.getContentByLineEl(lineEl);
      if (!contentText) {
        return;
      }
      const contentTd = contentText.parentElement;
      if (!contentTd.contains(node)) {
        node = contentText;
        column = 0;
      } else {
        const thread = contentTd.querySelector('gr-diff-comment-thread');
        if (thread && thread.contains(node)) {
          column = this._getLength(contentText);
          node = contentText;
        } else {
          column = this._convertOffsetToColumn(node, offset);
        }
      }

      return {
        node,
        side,
        line,
        column,
      };
    },

    _handleSelection() {
      const normalizedRange = this._getNormalizedRange();
      if (!normalizedRange) {
        return;
      }
      const domRange = window.getSelection().getRangeAt(0);
      const start = normalizedRange.start;
      if (!start) {
        return;
      }
      const end = normalizedRange.end;
      if (!end) {
        return;
      }
      if (start.side !== end.side ||
          end.line < start.line ||
          (start.line === end.line && start.column === end.column)) {
        return;
      }

      // TODO (viktard): Drop empty first and last lines from selection.

      const actionBox = document.createElement('gr-selection-action-box');
      const root = Polymer.dom(this.root);
      root.insertBefore(actionBox, root.firstElementChild);
      actionBox.range = {
        startLine: start.line,
        startChar: start.column,
        endLine: end.line,
        endChar: end.column,
      };
      actionBox.side = start.side;
      if (start.line === end.line) {
        actionBox.placeAbove(domRange);
      } else if (start.node instanceof Text) {
        actionBox.placeAbove(start.node.splitText(start.column));
        start.node.parentElement.normalize(); // Undo splitText from above.
      } else if (start.node.classList.contains('content') &&
                 start.node.firstChild) {
        actionBox.placeAbove(start.node.firstChild);
      } else {
        actionBox.placeAbove(start.node);
      }
    },

    _createComment(e) {
      this._removeActionBox();
    },

    _removeActionBoxDebounced() {
      this.debounce('removeActionBox', this._removeActionBox, 10);
    },

    _removeActionBox() {
      const actionBox = this.$$('gr-selection-action-box');
      if (actionBox) {
        Polymer.dom(this.root).removeChild(actionBox);
      }
    },

    _convertOffsetToColumn(el, offset) {
      if (el instanceof Element && el.classList.contains('content')) {
        return offset;
      }
      while (el.previousSibling ||
          !el.parentElement.classList.contains('content')) {
        if (el.previousSibling) {
          el = el.previousSibling;
          offset += this._getLength(el);
        } else {
          el = el.parentElement;
        }
      }
      return offset;
    },

    /**
     * Traverse Element from right to left, call callback for each node.
     * Stops if callback returns true.
     *
     * @param {!Node} startNode
     * @param {function(Node):boolean} callback
     * @param {Object=} opt_flags If flags.left is true, traverse left.
     */
    _traverseContentSiblings(startNode, callback, opt_flags) {
      const travelLeft = opt_flags && opt_flags.left;
      let node = startNode;
      while (node) {
        if (node instanceof Element &&
            node.tagName !== 'HL' &&
            node.tagName !== 'SPAN') {
          break;
        }
        const nextNode = travelLeft ? node.previousSibling : node.nextSibling;
        if (callback(node)) {
          break;
        }
        node = nextNode;
      }
    },

    /**
     * Get length of a node. If the node is a content node, then only give the
     * length of its .contentText child.
     *
     * @param {!Node} node
     * @return {number}
     */
    _getLength(node) {
      if (node instanceof Element && node.classList.contains('content')) {
        return this._getLength(node.querySelector('.contentText'));
      } else {
        return GrAnnotation.getLength(node);
      }
    },
  });
})();
<|endoftext|>


<commit_before>/*jslint node: true */
"use strict";

var dualapi = require('../index');
var _ = require('underscore');
var assert = require('assert');

describe('dualapi', function () {

    describe('open', function () {

        var dual = dualapi();

        describe('send', function () {

            it('should listen for dual messages on the socket', function (done) {
                dual.open(['rue'], {
                    on: function (target, cb) {
                        if (target == 'dual') {
                            done();
                        }
                    }
                });
            });

            it('should listen for disconnect messages on the socket', function (done) {
                dual.open(['rue2'], {
                    on: function (target, cb) {
                        if (target == 'disconnect') {
                            done();
                        }
                    }
                });
            });

            it('should echo dual messages to the domain with the destination', function (done) {
                dual.mount(['voiture'], function () {
                    done();
                });
                dual.open(['rue3'], {
                    on: function (target, cb) {
                        if (target === 'dual') {
                            cb({
                                to: ['voiture']
                            });
                        }
                    }
                });
            });

            it('should echo dual messages to the domain preserving body', function (done) {
                dual.mount(['voiture2'], function (ctxt) {
                    assert.deepEqual(ctxt.body, {prendre: 'gauche'});
                    done();
                });
                dual.open(['rue3'], {
                    on: function (target, cb) {
                        if (target === 'dual') {
                            cb({
                                to: ['voiture2']
                                , body: {prendre: 'gauche'}
                            });
                        }
                    }
                });
            });

            it('should translate the from field', function (done) {
                dual.mount(['voiture3'], function (ctxt) {
                    assert.deepEqual(ctxt.from, ['rue4', 'amerique']);
                    done();
                });
                dual.open(['rue4'], {
                    on: function (target, cb) {
                        if (target === 'dual') {
                            cb({
                                to: ['voiture3']
                                , from: ['amerique']
                            });
                        }
                    }
                });
            });

        });

        describe('firewall', function () {

            it('should be able to filter messages', function (done) {
                var called = 0;
                dual.mount(['voiture6', '*'], function () {
                    called++;
                });
                dual.open(['rue3'], {
                    on: function (target, cb) {
                        if (target === 'dual') {
                            cb({ to: ['voiture6', 'red']});
                            cb({ to: ['voiture6', 'rouge']});
                            assert.equal(called, 1);
                            done();
                        }
                    }
                }, function (ctxt, pass) {
                    return pass(ctxt.to[1] === 'rouge');
                });
            });
        });

    });

});
<commit_msg>Add socket receive and disconnect tests.<commit_after>/*jslint node: true */
"use strict";

var dualapi = require('../index');
var _ = require('underscore');
var assert = require('assert');

describe('dualapi', function () {

    describe('open', function () {

        var dual = dualapi();

        describe('send', function () {

            it('should listen for dual messages on the socket', function (done) {
                dual.open(['rue'], {
                    on: function (target, cb) {
                        if (target == 'dual') {
                            done();
                        }
                    }
                });
            });

            it('should listen for disconnect messages on the socket', function (done) {
                dual.open(['rue2'], {
                    on: function (target, cb) {
                        if (target == 'disconnect') {
                            done();
                        }
                    }
                });
            });

            it('should echo dual messages to the domain with the destination', function (done) {
                dual.mount(['voiture'], function () {
                    done();
                });
                dual.open(['rue3'], {
                    on: function (target, cb) {
                        if (target === 'dual') {
                            cb({
                                to: ['voiture']
                            });
                        }
                    }
                });
            });

            it('should echo dual messages to the domain preserving body', function (done) {
                dual.mount(['voiture2'], function (ctxt) {
                    assert.deepEqual(ctxt.body, {prendre: 'gauche'});
                    done();
                });
                dual.open(['rue3'], {
                    on: function (target, cb) {
                        if (target === 'dual') {
                            cb({
                                to: ['voiture2']
                                , body: {prendre: 'gauche'}
                            });
                        }
                    }
                });
            });

            it('should translate the from field', function (done) {
                dual.mount(['voiture3'], function (ctxt) {
                    assert.deepEqual(ctxt.from, ['rue4', 'amerique']);
                    done();
                });
                dual.open(['rue4'], {
                    on: function (target, cb) {
                        if (target === 'dual') {
                            cb({
                                to: ['voiture3']
                                , from: ['amerique']
                            });
                        }
                    }
                });
            });

        });

        describe('firewall', function () {

            it('should be able to filter messages', function (done) {
                var called = 0;
                dual.mount(['voiture6', '*'], function () {
                    called++;
                });
                dual.open(['rue3'], {
                    on: function (target, cb) {
                        if (target === 'dual') {
                            cb({ to: ['voiture6', 'red']});
                            cb({ to: ['voiture6', 'rouge']});
                            assert.equal(called, 1);
                            done();
                        }
                    }
                }, function (ctxt, pass) {
                    return pass(ctxt.to[1] === 'rouge');
                });
            });
        });

        describe('receive', function () {

            it('dual should transfer messages targeted to the mount point on "dual" channel', function (done) {

                dual.open(['wormhole'], {
                    on: function (target, cb) {}
                    , emit: function (target) {
                        assert.equal(target, 'dual');
                        done();
                    }
                });
                dual.send(['wormhole']);

            });

            it('dual should transfer messages targeted below the mount point on "dual" channel', function (done) {

                dual.open(['wormhole1'], {
                    on: function (target, cb) {}
                    , emit: function (target) {
                        assert.equal(target, 'dual');
                        done();
                    }
                });
                dual.send(['wormhole1', 'delta']);
            });

            it('dual should transfer the json context, preserving from field', function (done) {

                dual.open(['wormhole2'], {
                    on: function (target, cb) {}
                    , emit: function (target, msg) {
                        assert.deepEqual(msg.from, ['bajor']);
                        done();
                    }
                });
                dual.send(['wormhole2', 'delta'], ['bajor']);
            });

            it('dual should transfer the json context, preserving body field', function (done) {

                dual.open(['wormhole3'], {
                    on: function (target, cb) {}
                    , emit: function (target, msg) {
                        assert.deepEqual(msg.body, {captain: 'sisko'});
                        done();
                    }
                });
                dual.send(['wormhole3', 'delta'], ['bajor'], { captain: 'sisko'});
            });

            it('dual should transfer the json context, translating the to field', function (done) {

                dual.open(['wormhole4'], {
                    on: function (target, cb) {}
                    , emit: function (target, msg) {
                        assert.deepEqual(msg.to, ['delta']);
                        done();
                    }
                });
                dual.send(['wormhole4', 'delta'], { captain: 'sisko'});
            });

        });

        describe('disconnect', function () {

            it('dual should stop sending messages to the mounted host after disconnect', function () {
                var mockSocket = {};
                var called = 0;
                dual.mount(['sector'], function () {
                    called++;
                });
                dual.open(['deepspace'], {
                    on: function (target, cb) {
                        mockSocket[target] = cb;
                    }
                    , off: function () {}
                    , emit: function () {
                        called++;
                    }
                });
                dual.send(['deepspace']);
                mockSocket.disconnect();
                dual.send(['deepspace']);
                assert.equal(called, 1);
            });

            it('dual should stop sending messages below the mounted host after disconnect', function () {
                var mockSocket = {};
                var called = 0;
                dual.mount(['sector2'], function () {
                    called++;
                });
                dual.open(['deepspace2'], {
                    on: function (target, cb) {
                        mockSocket[target] = cb;
                    }
                    , off: function () {}
                    , emit: function () {
                        called++;
                    }
                });
                dual.send(['deepspace2', '1']);
                mockSocket.disconnect();
                dual.send(['deepspace2', '2']);
                assert.equal(called, 1);
            });

            it('dual should stop listening for dual messages on disconnect', function (done) {
                var mockSocket = {};
                dual.open(['deepspace3'], {
                    on: function (target, cb) {
                        mockSocket[target] = cb;
                    }
                    , off: function (target, cb) {
                        if (target == 'dual') {
                            done();
                        }
                    }
                });
                mockSocket.disconnect();
            });

            it('dual should stop listening for disconnect messages on disconnect', function (done) {
                var mockSocket = {};
                dual.open(['deepspace3'], {
                    on: function (target, cb) {
                        mockSocket[target] = cb;
                    }
                    , off: function (target, cb) {
                        if (target == 'disconnect') {
                            done();
                        }
                    }
                });
                mockSocket.disconnect();
            });

        });

    });

});
<|endoftext|>


<commit_before>/**
 * @class CM_Form_Abstract
 * @extends CM_View_Abstract
 */
var CM_Form_Abstract = CM_View_Abstract.extend({
	_class: 'CM_Form_Abstract',

	_fields: {},

	ready: function() {
	},

	_ready: function() {
		this._fields = {};
		_.each(this.options.fields, function(fieldInfo, name) {
			// Lazy construct
			var $field = this.$("#"+name);
			if ($field.length) {
				var fieldClass = window[fieldInfo.className];
				this.registerField(name,  new fieldClass({"el": $field, "parent": this, "name": name, "options": fieldInfo.options}));
			}
		}, this);

		var handler = this;

		_.each(this.options.actions, function(action, name) {
			var $btn = $('#'+this.getAutoId()+'-'+name+'-button');
			$btn.on('click', {action: name}, function(event) {
				handler.submit(event.data.action);
				return false;
			});
		}, this);

		if (this.options.default_action) {
			this.$().submit(function(event) {
				handler.submit(handler.default_action);
				return false;
			});
		}

		CM_View_Abstract.prototype._ready.call(this);
	},

	/**
	 * @param {String} name
	 * @param {CM_FormField_Abstract} field
	 */
	registerField: function(name, field) {
		this._fields[name] = field;

		field.on('change', function() {
			this.trigger('change');
		}, this);
	},

	/**
	 * @return CM_Component_Abstract
	 */
	getComponent: function() {
		return this.getParent();
	},

	/**
	 * @return CM_FormField_Abstract|null
	 */
	getField: function(name) {
		if (!this._fields[name]) {
			return null;
		}
		return this._fields[name];
	},

	/**
	 * @return jQuery
	 */
	$: function(selector) {
		if (!selector) {
			return this.$el;
		}
		selector = selector.replace('#', '#'+this.getAutoId()+'-');
		return $(selector, this.el);
	},

	/**
	 * @param {String|Null} actionName
	 */
	getData: function(actionName) {
		var form_data = this.$().serializeArray();
		var action = actionName ? this.options.actions[actionName] : null;

		var data = {};
		var regex = /^([\w\-]+)(\[([^\]]+)?\])?$/;
		var name, match;

		for (var i = 0, item; item = form_data[i]; i++) {
			match = regex.exec(item.name);
			name = match[1];
			item.value = item.value || '';

			if (action && typeof action.fields[name] == 'undefined') {
				continue;
			}

			if (!match[2]) {
				// Scalar
				data[name] = item.value;
			} else if (match[2] == '[]') {
				// Array
				if (typeof data[name] == 'undefined') {
					data[name] = [];
				}
				data[name].push(item.value);
			} else if (match[3]) {
				// Associative array
				if (typeof data[name] == 'undefined') {
					data[name] = {};
				}
				data[name][match[3]] = item.value;
			}
		}

		return data;
	},

	submit: function(actionName, confirmed, data, callbacks) {
		confirmed = confirmed || false;
		callbacks = callbacks || {};
		actionName = actionName || this.options.default_action;
		var action = this.options.actions[actionName];

		if (!confirmed) {
			$('.form_field_error', this.$())
				.next('br').remove()
				.addBack().remove();
		}

		data = data || this.getData(actionName);

		var hasErrors = false;
		_.each(_.keys(action.fields).reverse(), function(fieldName) {
			var required = action.fields[fieldName];
			if (required && _.isEmpty(data[fieldName])) {
				var field = this.getField(fieldName);
				var label;
				var errorMessage = cm.language.get('Required');
				var $textInput = field.$('input, textarea');
				var $labels = $('label[for="' + field.getAutoId() + '-input"]');
				if ($labels.length) {
					label = $labels.first().text();
				} else if ($textInput.attr('placeholder')) {
					label = $textInput.attr('placeholder');
				}
				if (label) {
					errorMessage = cm.language.get('{$label} is required.', {label: label});
				}
				field.error(errorMessage);
				hasErrors = true;
			}
		}, this);
		if (hasErrors) {
			return false;
		}

		if (action.confirm_msg && !confirmed) {
			cm.ui.confirm(cm.language.get(action.confirm_msg), function() {
				this.submit(actionName, true, data);
			}, this);
			return false;
		}

		var handler = this;
		this.disable();
		this.trigger('submit', [data]);
		cm.ajax('form', {view:this.getComponent()._getArray(), form:this._getArray(), actionName:actionName, data:data}, {
			success: function(response) {
				if (response.errors) {
					for (var i = response.errors.length-1, error; error = response.errors[i]; i--) {
						if (_.isArray(error)) {
							handler.getField(error[1]).error(error[0]);
						} else {
							handler.error(error);
						}
					}
					handler.trigger('error');
				}

				if (response.exec) {
					handler.evaluation = new Function(response.exec);
					handler.evaluation();
				}

				if (callbacks.success) {
					callbacks.success();
				}

				if (response.messages) {
					for (var i = 0, msg; msg = response.messages[i]; i++) {
						handler.message(msg);
					}
				}

				if (!response.errors) {
					handler.trigger('success success.' + actionName, response.data);
				}
			},
			complete: function() {
				handler.enable();
				handler.trigger('complete');
			}
		});
	},

	reset: function() {
		this.$().get(0).reset();
	},

	disable: function() {
		this.$().disable();
	},

	enable: function() {
		this.$().enable();
	},

	/**
	 * @param {String} message
	 */
	error: function(message) {
		cm.window.hint(message);
	},

	/**
	 * @param {String} message
	 */
	message: function(message) {
		cm.window.hint(message);
	}
});
<commit_msg>Move formField initialization from form's ready to initialize<commit_after>/**
 * @class CM_Form_Abstract
 * @extends CM_View_Abstract
 */
var CM_Form_Abstract = CM_View_Abstract.extend({
	_class: 'CM_Form_Abstract',

	_fields: {},

	ready: function() {
	},

	initialize: function() {
		CM_View_Abstract.prototype.initialize.call(this);

		this._fields = {};
		_.each(this.options.fields, function(fieldInfo, name) {
			// Lazy construct
			var $field = this.$("#"+name);
			if ($field.length) {
				var fieldClass = window[fieldInfo.className];
				this.registerField(name,  new fieldClass({"el": $field, "parent": this, "name": name, "options": fieldInfo.options}));
			}
		}, this);
	},

	_ready: function() {
		var handler = this;

		_.each(this.options.actions, function(action, name) {
			var $btn = $('#'+this.getAutoId()+'-'+name+'-button');
			$btn.on('click', {action: name}, function(event) {
				handler.submit(event.data.action);
				return false;
			});
		}, this);

		if (this.options.default_action) {
			this.$().submit(function(event) {
				handler.submit(handler.default_action);
				return false;
			});
		}

		CM_View_Abstract.prototype._ready.call(this);
	},

	/**
	 * @param {String} name
	 * @param {CM_FormField_Abstract} field
	 */
	registerField: function(name, field) {
		this._fields[name] = field;

		field.on('change', function() {
			this.trigger('change');
		}, this);
	},

	/**
	 * @return CM_Component_Abstract
	 */
	getComponent: function() {
		return this.getParent();
	},

	/**
	 * @return CM_FormField_Abstract|null
	 */
	getField: function(name) {
		if (!this._fields[name]) {
			return null;
		}
		return this._fields[name];
	},

	/**
	 * @return jQuery
	 */
	$: function(selector) {
		if (!selector) {
			return this.$el;
		}
		selector = selector.replace('#', '#'+this.getAutoId()+'-');
		return $(selector, this.el);
	},

	/**
	 * @param {String|Null} actionName
	 */
	getData: function(actionName) {
		var form_data = this.$().serializeArray();
		var action = actionName ? this.options.actions[actionName] : null;

		var data = {};
		var regex = /^([\w\-]+)(\[([^\]]+)?\])?$/;
		var name, match;

		for (var i = 0, item; item = form_data[i]; i++) {
			match = regex.exec(item.name);
			name = match[1];
			item.value = item.value || '';

			if (action && typeof action.fields[name] == 'undefined') {
				continue;
			}

			if (!match[2]) {
				// Scalar
				data[name] = item.value;
			} else if (match[2] == '[]') {
				// Array
				if (typeof data[name] == 'undefined') {
					data[name] = [];
				}
				data[name].push(item.value);
			} else if (match[3]) {
				// Associative array
				if (typeof data[name] == 'undefined') {
					data[name] = {};
				}
				data[name][match[3]] = item.value;
			}
		}

		return data;
	},

	submit: function(actionName, confirmed, data, callbacks) {
		confirmed = confirmed || false;
		callbacks = callbacks || {};
		actionName = actionName || this.options.default_action;
		var action = this.options.actions[actionName];

		if (!confirmed) {
			$('.form_field_error', this.$())
				.next('br').remove()
				.addBack().remove();
		}

		data = data || this.getData(actionName);

		var hasErrors = false;
		_.each(_.keys(action.fields).reverse(), function(fieldName) {
			var required = action.fields[fieldName];
			if (required && _.isEmpty(data[fieldName])) {
				var field = this.getField(fieldName);
				var label;
				var errorMessage = cm.language.get('Required');
				var $textInput = field.$('input, textarea');
				var $labels = $('label[for="' + field.getAutoId() + '-input"]');
				if ($labels.length) {
					label = $labels.first().text();
				} else if ($textInput.attr('placeholder')) {
					label = $textInput.attr('placeholder');
				}
				if (label) {
					errorMessage = cm.language.get('{$label} is required.', {label: label});
				}
				field.error(errorMessage);
				hasErrors = true;
			}
		}, this);
		if (hasErrors) {
			return false;
		}

		if (action.confirm_msg && !confirmed) {
			cm.ui.confirm(cm.language.get(action.confirm_msg), function() {
				this.submit(actionName, true, data);
			}, this);
			return false;
		}

		var handler = this;
		this.disable();
		this.trigger('submit', [data]);
		cm.ajax('form', {view:this.getComponent()._getArray(), form:this._getArray(), actionName:actionName, data:data}, {
			success: function(response) {
				if (response.errors) {
					for (var i = response.errors.length-1, error; error = response.errors[i]; i--) {
						if (_.isArray(error)) {
							handler.getField(error[1]).error(error[0]);
						} else {
							handler.error(error);
						}
					}
					handler.trigger('error');
				}

				if (response.exec) {
					handler.evaluation = new Function(response.exec);
					handler.evaluation();
				}

				if (callbacks.success) {
					callbacks.success();
				}

				if (response.messages) {
					for (var i = 0, msg; msg = response.messages[i]; i++) {
						handler.message(msg);
					}
				}

				if (!response.errors) {
					handler.trigger('success success.' + actionName, response.data);
				}
			},
			complete: function() {
				handler.enable();
				handler.trigger('complete');
			}
		});
	},

	reset: function() {
		this.$().get(0).reset();
	},

	disable: function() {
		this.$().disable();
	},

	enable: function() {
		this.$().enable();
	},

	/**
	 * @param {String} message
	 */
	error: function(message) {
		cm.window.hint(message);
	},

	/**
	 * @param {String} message
	 */
	message: function(message) {
		cm.window.hint(message);
	}
});
<|endoftext|>


<commit_before>'use strict';

(function ($) {

    if (!$) { throw new Error('OpenSeadragon Annotations requires OpenSeadragon'); }

    $.Viewer.prototype.initializeAnnotations = function (options) {
        var options = $.extend({ viewer: this }, options);
        this.addHandler('open', annotations.onOpen.bind(annotations));
        this.annotations = this.annotations || annotations.initialize(options);
        return this;
    };

    var annotations = {

        initialize: function (options) {
            $.extend(this, {
                state: move.initialize(),
                controls: controls.initialize({
                    imagePath: options.imagePath || ''
                })
            }, options);
            this.controls.addHandler('add', function (button) {
                this.viewer.addControl(button.element, {
                    anchor: $.ControlAnchor.BOTTOM_LEFT
                });
            }.bind(this));
            return this;
        },

        onOpen: function () {
            this.overlay = overlay.initialize({
                viewer: this.viewer
            });

            this.viewer.addHandler('animation', function () {
                var width = this.overlay.el.clientWidth;
                var height = this.overlay.el.clientHeight;
                var viewPort = '0 0 ' + width + ' ' + height;
                var svg = this.overlay.el.querySelector('svg');
                svg.setAttribute('viewPort', viewPort);
            }.bind(this));

            this.controls.add('move', true).addHandler('click', function () {
                this.viewer.setMouseNavEnabled(true);
                this.state = move.initialize();
            }.bind(this));

            this.controls.add('draw').addHandler('click', function () {
                this.viewer.setMouseNavEnabled(false);
                this.state = draw.initialize();
            }.bind(this));

            this.overlay.el.addEventListener('mousedown', function (e) {
                this.state.handleMouseDown(e, this.overlay);
            }.bind(this), false);

            this.overlay.el.addEventListener('mouseup', function (e) {
                this.state.handleMouseUp(e, this.overlay);
            }.bind(this), false);

            return this;
        }

    };

    var state = {

        initialize: function (options) {
            $.extend(this, options);
            return this;
        },

        handleMouseDown: function () {
            return this;
        },

        handleMouseUp: function () {
            return this;
        }

    }

    var move = Object.create(state);

    var draw = $.extend(Object.create(state), {

        initialize: function (options) {
            $.extend(this, options);
            this._mouseTracker = function (e) {
                this.x = e.offsetX;
                this.y = e.offsetY;
            }.bind(this);
            return this;
        },

        handleMouseDown: function (e, overlay) {
            if (!this._interval) {
                this.x = e.offsetX;
                this.y = e.offsetY;
                var svg = overlay.el.querySelector('svg');
                var path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
                path.setAttribute('fill', 'none');
                path.setAttribute('stroke', 'red');
                path.setAttribute('stroke-width', '0.5');
                path.setAttribute('stroke-linejoin', 'round');
                path.setAttribute('stroke-linecap', 'round');
                path.setAttribute('d', 'M' + this.x / overlay.el.clientWidth * 100 +
                    ' ' + this.y / overlay.el.clientHeight * 100);
                svg.appendChild(path);

                overlay.el.addEventListener('mousemove', this._mouseTracker, false);

                this._interval = window.setInterval(function () {
                    path.setAttribute('d', path.getAttribute('d') +
                        ' L' + this.x / overlay.el.clientWidth * 100 +
                        ' ' + this.y / overlay.el.clientHeight * 100);
                }.bind(this), 25);
            }
            e.stopPropagation();
            return this;
        },

        handleMouseUp: function (e, overlay) {
            overlay.el.removeEventListener('mousemove', this._mouseTracker);
            this._interval = clearInterval(this._interval);
            return this;
        }

    });

    var controls = $.extend(new $.EventSource(), {

        initialize: function (options) {
            $.extend(this, options);
            this.list = {};
            this.addHandler('click', this.onClick.bind(this));
            return this;
        },

        onClick: function (name) {
            for (var button in this.list) {
                if (this.list.hasOwnProperty(button)) {
                    if (button === name) {
                        this.list[button].imgDown.style.visibility = 'visible';
                    } else {
                        this.list[button].imgDown.style.visibility = 'hidden';
                    }
                }
            }
            return this;
        },

        add: function (name, active) {
            this.list[name] = new $.Button({
                tooltip: name[0].toUpperCase() + name.substr(1),
                srcRest: this.imagePath + name + '_rest.png',
                srcGroup: this.imagePath + name + '_grouphover.png',
                srcHover: this.imagePath + name + '_hover.png',
                srcDown: this.imagePath + name + '_pressed.png',
                onClick: this.raiseEvent.bind(this, 'click', name)
            });
            if (active) {
                this.list[name].imgDown.style.visibility = 'visible';
            }
            this.raiseEvent('add', this.list[name]);
            return this.list[name];
        },

        get: function (name) {
            return this.list[name];
        }

    });

    var overlay = {

        initialize: function (options) {
            $.extend(this, options);
            this.el = document.createElement('div');
            this.el.className = 'overlay';
            var svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
            svg.setAttribute('version', '1.1');
            svg.setAttribute('width', '100%');
            svg.setAttribute('height', '100%');
            svg.setAttribute('preserveAspectRatio', 'none');
            svg.setAttribute('viewBox', '0 0 100 100')
            svg.style.cursor = 'default';
            this.el.appendChild(svg);
            var width = this.viewer.viewport.homeBounds.width;
            var height = this.viewer.viewport.homeBounds.height;
            this.viewer.addOverlay(this.el, new $.Rect(0, 0, width, height));
            return this;
        }

    };

})(OpenSeadragon);
<commit_msg>Small tidy up<commit_after>import annotations from './annotations';

(function ($) {

    if (!$) { throw new Error('OpenSeadragon Annotations requires OpenSeadragon'); }

    $.Viewer.prototype.initializeAnnotations = function (options) {
        this.addHandler('open', annotations.onOpen.bind(annotations));
        this.annotations = this.annotations || annotations.initialize($.extend({ viewer: this }, options));
        return this;
    };

    var annotations = {

        initialize: function (options) {
            $.extend(this, {
                state: move.initialize(),
                controls: controls.initialize({
                    imagePath: options.imagePath || ''
                })
            }, options);
            this.controls.addHandler('add', function (button) {
                this.viewer.addControl(button.element, {
                    anchor: $.ControlAnchor.BOTTOM_LEFT
                });
            }.bind(this));
            return this;
        },

        onOpen: function () {
            this.overlay = overlay.initialize({
                viewer: this.viewer
            });

            this.viewer.addHandler('animation', function () {
                var width = this.overlay.el.clientWidth;
                var height = this.overlay.el.clientHeight;
                var viewPort = '0 0 ' + width + ' ' + height;
                var svg = this.overlay.el.querySelector('svg');
                svg.setAttribute('viewPort', viewPort);
            }.bind(this));

            this.controls.add('move', true).addHandler('click', function () {
                this.viewer.setMouseNavEnabled(true);
                this.state = move.initialize();
            }.bind(this));

            this.controls.add('draw').addHandler('click', function () {
                this.viewer.setMouseNavEnabled(false);
                this.state = draw.initialize();
            }.bind(this));

            this.overlay.el.addEventListener('mousedown', function (e) {
                this.state.handleMouseDown(e, this.overlay);
            }.bind(this), false);

            this.overlay.el.addEventListener('mouseup', function (e) {
                this.state.handleMouseUp(e, this.overlay);
            }.bind(this), false);

            return this;
        }

    };

    var state = {

        initialize: function (options) {
            $.extend(this, options);
            return this;
        },

        handleMouseDown: function () {
            return this;
        },

        handleMouseUp: function () {
            return this;
        }

    };

    var move = Object.create(state);

    var draw = $.extend(Object.create(state), {

        initialize: function (options) {
            $.extend(this, options);
            this._mouseTracker = function (e) {
                this.x = e.offsetX;
                this.y = e.offsetY;
            }.bind(this);
            return this;
        },

        handleMouseDown: function (e, overlay) {
            if (!this._interval) {
                this.x = e.offsetX;
                this.y = e.offsetY;
                var svg = overlay.el.querySelector('svg');
                var path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
                path.setAttribute('fill', 'none');
                path.setAttribute('stroke', 'red');
                path.setAttribute('stroke-width', '0.5');
                path.setAttribute('stroke-linejoin', 'round');
                path.setAttribute('stroke-linecap', 'round');
                path.setAttribute('d', 'M' + this.x / overlay.el.clientWidth * 100 +
                    ' ' + this.y / overlay.el.clientHeight * 100);
                svg.appendChild(path);

                overlay.el.addEventListener('mousemove', this._mouseTracker, false);

                this._interval = window.setInterval(function () {
                    path.setAttribute('d', path.getAttribute('d') +
                        ' L' + this.x / overlay.el.clientWidth * 100 +
                        ' ' + this.y / overlay.el.clientHeight * 100);
                }.bind(this), 25);
            }
            e.stopPropagation();
            return this;
        },

        handleMouseUp: function (e, overlay) {
            overlay.el.removeEventListener('mousemove', this._mouseTracker);
            this._interval = clearInterval(this._interval);
            return this;
        }

    });

    var controls = $.extend(new $.EventSource(), {

        initialize: function (options) {
            $.extend(this, options);
            this.list = {};
            this.addHandler('click', this.onClick.bind(this));
            return this;
        },

        onClick: function (name) {
            for (var button in this.list) {
                if (this.list.hasOwnProperty(button)) {
                    if (button === name) {
                        this.list[button].imgDown.style.visibility = 'visible';
                    } else {
                        this.list[button].imgDown.style.visibility = 'hidden';
                    }
                }
            }
            return this;
        },

        add: function (name, active) {
            this.list[name] = new $.Button({
                tooltip: name[0].toUpperCase() + name.substr(1),
                srcRest: this.imagePath + name + '_rest.png',
                srcGroup: this.imagePath + name + '_grouphover.png',
                srcHover: this.imagePath + name + '_hover.png',
                srcDown: this.imagePath + name + '_pressed.png',
                onClick: this.raiseEvent.bind(this, 'click', name)
            });
            if (active) {
                this.list[name].imgDown.style.visibility = 'visible';
            }
            this.raiseEvent('add', this.list[name]);
            return this.list[name];
        },

        get: function (name) {
            return this.list[name];
        }

    });

    var overlay = {

        initialize: function (options) {
            $.extend(this, options);
            this.el = document.createElement('div');
            this.el.className = 'overlay';
            var svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
            svg.setAttribute('version', '1.1');
            svg.setAttribute('width', '100%');
            svg.setAttribute('height', '100%');
            svg.setAttribute('preserveAspectRatio', 'none');
            svg.setAttribute('viewBox', '0 0 100 100')
            svg.style.cursor = 'default';
            this.el.appendChild(svg);
            var width = this.viewer.viewport.homeBounds.width;
            var height = this.viewer.viewport.homeBounds.height;
            this.viewer.addOverlay(this.el, new $.Rect(0, 0, width, height));
            return this;
        }

    };

})(OpenSeadragon);
<|endoftext|>