<commit_before>var inherits = require('util').inherits

var _ = require('lodash')
var io = require('socket.io-client')
var ws = require('ws')

var Network = require('./network')
var errors = require('../errors')
var util = require('../util')
var yatc = require('../yatc')

/**
 * [ElectrumJS api]{@link https://github.com/fanatid/electrumjs-server}
 *
 * @class ElectrumJS
 * @extends Network
 *
 * @param {Object} [opts]
 * @param {boolean} [opts.testnet=false]
 * @param {string} [opts.url=ws://devel.hz.udoidio.info:878x]
 */
function ElectrumJS(opts) {
  opts = _.extend({
    testnet: false,
    url: 'ws://devel.hz.udoidio.info:' + (!!opts.testnet ? '8784' : '8783')
  }, opts)

  yatc.verify('{testnet: Boolean, url: String}', opts)

  var self = this
  Network.call(self)

  self._requestId = 0
  self._requests = {}
  self._subscribedAddresses = []
  self._lastResponse = Date.now()

  self._socket = io(opts.url, {
    autoConnect: false,
    forceNew: true,
    reconnectionDelay: 10000,
    reconnectionDelayMax: 10000,
    randomizationFactor: 0,
    forceJSONP: false,
    jsonp: true,
    transports: ws !== null ? ['websocket', 'polling'] : ['polling']
  })

  self._socket.on('connect_error', function (error) { self.emit('error', error) })
  self._socket.on('error', function (error) { self.emit('error', error) })

  self._socket.on('connect', function () { self.emit('connect') })
  self._socket.on('disconnect', function () { self.emit('disconnect') })

  self._socket.on('message', function (response) {
    self._lastResponse = Date.now()

    try {
      response = JSON.parse(response)

    } catch (error) {
      return self.emit('error', error)

    }

    if (response.id === null) {
      var isMethod = response.method === 'blockchain.numblocks.subscribe'
      var isArgs = yatc.is('(PositiveNumber)', response.params)
      if (isMethod && isArgs) {
        return self._setCurrentHeight(response.params[0])
      }

      isMethod = response.method === 'blockchain.address.subscribe'
      isArgs = yatc.is('(BitcoinAddress, String)', response.params)
      if (isMethod && isArgs) {
        return self.emit('touchAddress', response.params[0])
      }
    }

    var deferred = self._requests[response.id]
    if (typeof deferred === 'undefined') {
      return
    }

    if (typeof response.error === 'undefined') {
      deferred.resolve(response.result)

    } else {
      deferred.reject(new errors.ElectrumJSError(response.error))

    }

    delete self._requests[response.id]
  })

  self.on('connect', function () {
    self.refresh()
      .catch(function (error) { self.emit('error', error) })

    var addresses = self._subscribedAddresses
    self._subscribedAddresses = []
    addresses.forEach(self.subscribeAddress.bind(self))
  })

  self.on('disconnect', function () {
    var error = new errors.ElectrumJSError('Network unreachable')
    _.forEach(self._requests, function (deferred) {
      deferred.reject(error)
    })

    self._requestId = 0
    self._requests = {}
  })
}

inherits(ElectrumJS, Network)

/**
 * @private
 * @param {string} method
 * @param {Array.<*>} [params=[]]
 * @return {Promise}
 */
ElectrumJS.prototype._request = function (method, params) {
  if (typeof params === 'undefined') {
    params = []
  }

  yatc.verify('String', method)
  yatc.verify('[*]', params)

  var self = this
  if (!self.isConnected()) {
    return Promise.reject(new errors.NotConnectedError(method))
  }

  return new Promise(function (resolve, reject) {
    var request = {id: self._requestId++, method: method, params: params}
    self._requests[request.id] = {resolve: resolve, reject: reject}

    self._socket.send(JSON.stringify(request))
  })
}

/**
 * @return {boolean}
 */
ElectrumJS.prototype.supportVerificationMethods = function () {
  return true
}

/**
 * @memberof ElectrumJS.prototype
 * @method connect
 * @see {@link Network#connect}
 */
ElectrumJS.prototype.connect = function () { this._socket.connect() }

/**
 * @memberof ElectrumJS.prototype
 * @method disconnect
 * @see {@link Network#disconnect}
 */
ElectrumJS.prototype.disconnect = function () { this._socket.disconnect() }

/**
 * @memberof ElectrumJS.prototype
 * @method refresh
 * @see {@link Network#refresh}
 */
ElectrumJS.prototype.refresh = function () {
  var self = this
  return self._request('blockchain.numblocks.subscribe')
    .then(function (height) {
      yatc.verify('PositiveNumber', height)

      if (self.getCurrentHeight() !== height) {
        return self._setCurrentHeight(height)
      }
    })
}

/**
 * @memberof ElectrumJS.prototype
 * @method getCurrentActiveRequests
 * @see {@link Network#getCurrentActiveRequests}
 */
ElectrumJS.prototype.getCurrentActiveRequests = function () {
  return _.keys(this._requests).length
}

/**
 * @memberof ElectrumJS.prototype
 * @method getTimeFromLastResponse
 * @see {@link Network#getTimeFromLastResponse}
 */
ElectrumJS.prototype.getTimeFromLastResponse = function () {
  return Date.now() - this._lastResponse
}

/**
 * @memberof ElectrumJS.prototype
 * @method getHeader
 * @see {@link Network#getHeader}
 */
ElectrumJS.prototype.getHeader = function (height) {
  yatc.verify('PositiveNumber|ZeroNumber', height)

  return this._request('blockchain.block.get_header', [height])
    .then(function (response) {
      if (yatc.is('{block_height: ZeroNumber, ...}', response)) {
        response.prev_block_hash = util.zfill('', 64)
      }

      if (response.block_height !== height) {
        throw new errors.GetHeaderError()
      }

      yatc.verify('ElectrumHeader', response)

      return {
        version: response.version,
        prevBlockHash: response.prev_block_hash,
        merkleRoot: response.merkle_root,
        timestamp: response.timestamp,
        bits: response.bits,
        nonce: response.nonce
      }
    })
}

/**
 * @memberof ElectrumJS.prototype
 * @method getChunk
 * @see {@link Network#getChunk}
 */
ElectrumJS.prototype.getChunk = function (index) {
  yatc.verify('PositiveNumber|ZeroNumber', index)

  return this._request('blockchain.block.get_chunk', [index])
    .then(function (chunkHex) {
      yatc.verify('BitcoinChunk', chunkHex)
      return chunkHex
    })
}

/**
 * @memberof ElectrumJS.prototype
 * @method getTx
 * @see {@link Network#getTx}
 */
ElectrumJS.prototype.getTx = function (txId) {
  yatc.verify('SHA256Hex', txId)

  return this._request('blockchain.transaction.get', [txId])
    .then(function (rawTx) {
      yatc.verify('HexString', rawTx)

      var responseTxId = util.hashEncode(util.sha256x2(new Buffer(rawTx, 'hex')))
      if (responseTxId === txId) {
        return rawTx
      }

      throw new errors.GetTxError('Expected: ' + txId + ', got: ' + responseTxId)
    })
}

/**
 * @memberof ElectrumJS.prototype
 * @method getMerkle
 * @see {@link Network#getMerkle}
 */
ElectrumJS.prototype.getMerkle = function (txId, height) {
  yatc.verify('Arguments{0: SHA256Hex, 1: Number|Undefined}', arguments)

  return this._request('blockchain.transaction.get_merkle', [txId, height])
    .then(function (response) {
      yatc.verify('ElectrumMerkle', response)

      return {
        height: response.block_height,
        merkle: response.merkle,
        index: response.pos
      }
    })
}

/**
 * @memberof ElectrumJS.prototype
 * @method sendTx
 * @see {@link Network#sendTx}
 */
ElectrumJS.prototype.sendTx = function (txHex) {
  yatc.verify('HexString', txHex)

  return this._request('blockchain.transaction.broadcast', [txHex])
    .then(function (responseTxId) {
      var txId = util.hashEncode(util.sha256x2(new Buffer(txHex, 'hex')))
      if (txId === responseTxId) {
        return txId
      }

      throw new errors.SendTxError('Expected: ' + txId + ', got: ' + responseTxId)
    })
}

/**
 * @memberof ElectrumJS.prototype
 * @method getHistory
 * @see {@link Network#getHistory}
 */
ElectrumJS.prototype.getHistory = function (address) {
  yatc.verify('BitcoinAddress', address)

  return this._request('blockchain.address.get_history', [address])
    .then(function (entries) {
      yatc.verify('[ElectrumHistoryEntry]', entries)

      return _.chain(entries)
        .map(function (entry) {
          return {txId: entry.tx_hash, height: entry.height || null}
        })
        .sortBy(function (entry) {
          return [entry.height === null ? Infinity : entry.height, entry.txId]
        })
        .value()
    })
}

/**
 * @memberof ElectrumJS.prototype
 * @method getUnspent
 * @see {@link Network#getUnspent}
 */
ElectrumJS.prototype.getUnspent = function (address) {
  yatc.verify('BitcoinAddress', address)

  return this._request('blockchain.address.listunspent', [address])
    .then(function (unspent) {
      yatc.verify('[ElectrumUnspent]', unspent)

      return _.chain(unspent)
        .map(function (entry) {
          return {
            txId: entry.tx_hash,
            outIndex: entry.tx_pos,
            value: entry.value,
            height: entry.height || null
          }
        })
        .sortBy(function (entry) {
          return [entry.height === null ? Infinity : entry.height, entry.txId]
        })
        .value()
    })
}

/**
 * @memberof ElectrumJS.prototype
 * @method subscribeAddress
 * @see {@link Network#subscribeAddress}
 */
ElectrumJS.prototype.subscribeAddress = util.makeSerial(function (address) {
  yatc.verify('BitcoinAddress', address)

  var self = this
  if (self._subscribedAddresses.indexOf(address) !== -1) {
    return Promise.resolve()
  }

  return self._request('blockchain.address.subscribe', [address])
    .then(function () { self._subscribedAddresses.push(address) })
})

module.exports = ElectrumJS
<commit_msg>fix disconnect event in electrumjs<commit_after>var inherits = require('util').inherits

var _ = require('lodash')
var io = require('socket.io-client')
var ws = require('ws')

var Network = require('./network')
var errors = require('../errors')
var util = require('../util')
var yatc = require('../yatc')

/**
 * [ElectrumJS api]{@link https://github.com/fanatid/electrumjs-server}
 *
 * @class ElectrumJS
 * @extends Network
 *
 * @param {Object} [opts]
 * @param {boolean} [opts.testnet=false]
 * @param {string} [opts.url=ws://devel.hz.udoidio.info:878x]
 */
function ElectrumJS(opts) {
  opts = _.extend({
    testnet: false,
    url: 'ws://devel.hz.udoidio.info:' + (!!opts.testnet ? '8784' : '8783')
  }, opts)

  yatc.verify('{testnet: Boolean, url: String}', opts)

  var self = this
  Network.call(self)

  self._requestId = 0
  self._requests = {}
  self._subscribedAddresses = []
  self._lastResponse = Date.now()

  self._socket = io(opts.url, {
    autoConnect: false,
    forceNew: true,
    reconnectionDelay: 10000,
    reconnectionDelayMax: 10000,
    randomizationFactor: 0,
    forceJSONP: false,
    jsonp: true,
    transports: ws !== null ? ['websocket', 'polling'] : ['polling']
  })

  self._socket.on('connect_error', function (error) { self.emit('error', error) })
  self._socket.on('error', function (error) { self.emit('error', error) })

  self._socket.on('connect', function () {
    if (!self.isConnected()) {
      self.emit('connect')
    }
  })
  self._socket.on('disconnect', function () {
    // prevent double event from socket on close/disconnect
    if (self.isConnected()) {
      self.emit('disconnect')
    }
  })

  self._socket.on('message', function (response) {
    self._lastResponse = Date.now()

    try {
      response = JSON.parse(response)

    } catch (error) {
      return self.emit('error', error)

    }

    if (response.id === null) {
      var isMethod = response.method === 'blockchain.numblocks.subscribe'
      var isArgs = yatc.is('(PositiveNumber)', response.params)
      if (isMethod && isArgs) {
        return self._setCurrentHeight(response.params[0])
      }

      isMethod = response.method === 'blockchain.address.subscribe'
      isArgs = yatc.is('(BitcoinAddress, String)', response.params)
      if (isMethod && isArgs) {
        return self.emit('touchAddress', response.params[0])
      }
    }

    var deferred = self._requests[response.id]
    if (typeof deferred === 'undefined') {
      return
    }

    if (typeof response.error === 'undefined') {
      deferred.resolve(response.result)

    } else {
      deferred.reject(new errors.ElectrumJSError(response.error))

    }

    delete self._requests[response.id]
  })

  self.on('connect', function () {
    self.refresh()
      .catch(function (error) { self.emit('error', error) })

    var addresses = self._subscribedAddresses
    self._subscribedAddresses = []
    addresses.forEach(self.subscribeAddress.bind(self))
  })

  self.on('disconnect', function () {
    var error = new errors.ElectrumJSError('Network unreachable')
    _.forEach(self._requests, function (deferred) {
      deferred.reject(error)
    })

    self._requestId = 0
    self._requests = {}
  })
}

inherits(ElectrumJS, Network)

/**
 * @private
 * @param {string} method
 * @param {Array.<*>} [params=[]]
 * @return {Promise}
 */
ElectrumJS.prototype._request = function (method, params) {
  if (typeof params === 'undefined') {
    params = []
  }

  yatc.verify('String', method)
  yatc.verify('[*]', params)

  var self = this
  if (!self.isConnected()) {
    return Promise.reject(new errors.NotConnectedError(method))
  }

  return new Promise(function (resolve, reject) {
    var request = {id: self._requestId++, method: method, params: params}
    self._requests[request.id] = {resolve: resolve, reject: reject}

    self._socket.send(JSON.stringify(request))
  })
}

/**
 * @return {boolean}
 */
ElectrumJS.prototype.supportVerificationMethods = function () {
  return true
}

/**
 * @memberof ElectrumJS.prototype
 * @method connect
 * @see {@link Network#connect}
 */
ElectrumJS.prototype.connect = function () { this._socket.connect() }

/**
 * @memberof ElectrumJS.prototype
 * @method disconnect
 * @see {@link Network#disconnect}
 */
ElectrumJS.prototype.disconnect = function () { this._socket.disconnect() }

/**
 * @memberof ElectrumJS.prototype
 * @method refresh
 * @see {@link Network#refresh}
 */
ElectrumJS.prototype.refresh = function () {
  var self = this
  return self._request('blockchain.numblocks.subscribe')
    .then(function (height) {
      yatc.verify('PositiveNumber', height)

      if (self.getCurrentHeight() !== height) {
        return self._setCurrentHeight(height)
      }
    })
}

/**
 * @memberof ElectrumJS.prototype
 * @method getCurrentActiveRequests
 * @see {@link Network#getCurrentActiveRequests}
 */
ElectrumJS.prototype.getCurrentActiveRequests = function () {
  return _.keys(this._requests).length
}

/**
 * @memberof ElectrumJS.prototype
 * @method getTimeFromLastResponse
 * @see {@link Network#getTimeFromLastResponse}
 */
ElectrumJS.prototype.getTimeFromLastResponse = function () {
  return Date.now() - this._lastResponse
}

/**
 * @memberof ElectrumJS.prototype
 * @method getHeader
 * @see {@link Network#getHeader}
 */
ElectrumJS.prototype.getHeader = function (height) {
  yatc.verify('PositiveNumber|ZeroNumber', height)

  return this._request('blockchain.block.get_header', [height])
    .then(function (response) {
      if (yatc.is('{block_height: ZeroNumber, ...}', response)) {
        response.prev_block_hash = util.zfill('', 64)
      }

      if (response.block_height !== height) {
        throw new errors.GetHeaderError()
      }

      yatc.verify('ElectrumHeader', response)

      return {
        version: response.version,
        prevBlockHash: response.prev_block_hash,
        merkleRoot: response.merkle_root,
        timestamp: response.timestamp,
        bits: response.bits,
        nonce: response.nonce
      }
    })
}

/**
 * @memberof ElectrumJS.prototype
 * @method getChunk
 * @see {@link Network#getChunk}
 */
ElectrumJS.prototype.getChunk = function (index) {
  yatc.verify('PositiveNumber|ZeroNumber', index)

  return this._request('blockchain.block.get_chunk', [index])
    .then(function (chunkHex) {
      yatc.verify('BitcoinChunk', chunkHex)
      return chunkHex
    })
}

/**
 * @memberof ElectrumJS.prototype
 * @method getTx
 * @see {@link Network#getTx}
 */
ElectrumJS.prototype.getTx = function (txId) {
  yatc.verify('SHA256Hex', txId)

  return this._request('blockchain.transaction.get', [txId])
    .then(function (rawTx) {
      yatc.verify('HexString', rawTx)

      var responseTxId = util.hashEncode(util.sha256x2(new Buffer(rawTx, 'hex')))
      if (responseTxId === txId) {
        return rawTx
      }

      throw new errors.GetTxError('Expected: ' + txId + ', got: ' + responseTxId)
    })
}

/**
 * @memberof ElectrumJS.prototype
 * @method getMerkle
 * @see {@link Network#getMerkle}
 */
ElectrumJS.prototype.getMerkle = function (txId, height) {
  yatc.verify('Arguments{0: SHA256Hex, 1: Number|Undefined}', arguments)

  return this._request('blockchain.transaction.get_merkle', [txId, height])
    .then(function (response) {
      yatc.verify('ElectrumMerkle', response)

      return {
        height: response.block_height,
        merkle: response.merkle,
        index: response.pos
      }
    })
}

/**
 * @memberof ElectrumJS.prototype
 * @method sendTx
 * @see {@link Network#sendTx}
 */
ElectrumJS.prototype.sendTx = function (txHex) {
  yatc.verify('HexString', txHex)

  return this._request('blockchain.transaction.broadcast', [txHex])
    .then(function (responseTxId) {
      var txId = util.hashEncode(util.sha256x2(new Buffer(txHex, 'hex')))
      if (txId === responseTxId) {
        return txId
      }

      throw new errors.SendTxError('Expected: ' + txId + ', got: ' + responseTxId)
    })
}

/**
 * @memberof ElectrumJS.prototype
 * @method getHistory
 * @see {@link Network#getHistory}
 */
ElectrumJS.prototype.getHistory = function (address) {
  yatc.verify('BitcoinAddress', address)

  return this._request('blockchain.address.get_history', [address])
    .then(function (entries) {
      yatc.verify('[ElectrumHistoryEntry]', entries)

      return _.chain(entries)
        .map(function (entry) {
          return {txId: entry.tx_hash, height: entry.height || null}
        })
        .sortBy(function (entry) {
          return [entry.height === null ? Infinity : entry.height, entry.txId]
        })
        .value()
    })
}

/**
 * @memberof ElectrumJS.prototype
 * @method getUnspent
 * @see {@link Network#getUnspent}
 */
ElectrumJS.prototype.getUnspent = function (address) {
  yatc.verify('BitcoinAddress', address)

  return this._request('blockchain.address.listunspent', [address])
    .then(function (unspent) {
      yatc.verify('[ElectrumUnspent]', unspent)

      return _.chain(unspent)
        .map(function (entry) {
          return {
            txId: entry.tx_hash,
            outIndex: entry.tx_pos,
            value: entry.value,
            height: entry.height || null
          }
        })
        .sortBy(function (entry) {
          return [entry.height === null ? Infinity : entry.height, entry.txId]
        })
        .value()
    })
}

/**
 * @memberof ElectrumJS.prototype
 * @method subscribeAddress
 * @see {@link Network#subscribeAddress}
 */
ElectrumJS.prototype.subscribeAddress = util.makeSerial(function (address) {
  yatc.verify('BitcoinAddress', address)

  var self = this
  if (self._subscribedAddresses.indexOf(address) !== -1) {
    return Promise.resolve()
  }

  return self._request('blockchain.address.subscribe', [address])
    .then(function () { self._subscribedAddresses.push(address) })
})

module.exports = ElectrumJS
<|endoftext|>


<commit_before>var fs = require('fs');
var git = require('gulp-git');
var gitStreaming = require('../util/git-streaming.js');
var gulp = require('gulp');
var highland = require('highland');
var metadataFilePaths = require('../util/metadata-file-paths.json');

gulp.task('bump-git-tag', function bumpGitTag(callback) {
  var package = JSON.parse(fs.readFileSync('package.json'));
  var version = package.version;

  gitStreaming.readTags
  .reduce(false, function checkTagExists(accumulator, tag) {
    if (accumulator || (tag === version)) {
      return true;
    }

    return false;
  })
  .each(function(tagExists) {
    if (tagExists) {
      return callback();
    }

    gulp.src(['./dist/*',
              './docs/*',
              'README.md']
              .concat(metadataFilePaths)
    )
    .pipe(highland.pipeline())
    .through(git.add())
    .through(git.commit('Built and bumped version to ' + version + '.'))
    .through(gitStreaming.createTag(version,
            'Version ' + version))
    .last()
    .each(function() {
      return callback();
    });
  });
});
<commit_msg>Working to correct error where package.json is updated after tag<commit_after>var fs = require('fs');
var git = require('gulp-git');
var gitStreaming = require('../util/git-streaming.js');
var gulp = require('gulp');
var highland = require('highland');
var metadataFilePaths = require('../util/metadata-file-paths.json');

gulp.task('bump-git-tag', function bumpGitTag(callback) {
  var package = JSON.parse(fs.readFileSync('package.json'));
  var version = package.version;

  gitStreaming.readTags
  .reduce(false, function checkTagExists(accumulator, tag) {
    if (accumulator || (tag === version)) {
      return true;
    }

    return false;
  })
  .each(function(tagExists) {
    if (tagExists) {
      return callback();
    }

    gulp.src(['./dist/*',
              './docs/*',
              'README.md']
              .concat(metadataFilePaths)
    )
    .pipe(highland.pipeline())
    .through(git.add())
    .through(git.commit('Built and bumped version to ' + version + '.'))
    .debounce(1000)
    .through(gitStreaming.createTag(version,
            'Version ' + version))
    .last()
    .each(function() {
      return callback();
    });
  });
});
<|endoftext|>


<commit_before>import { EnemyWidth, EnemyHeight, Border } from "../Constants.js";
import { getRandomArbitrary } from "../utils";

import Enemy from "objects/Enemy";

class EnemyGroup extends Phaser.Group {

  constructor(game, parent, name) {
    super(game, parent, name, false, true, Phaser.Physics.ARCADE);
    let nbEnemies = getRandomArbitrary(40,50);

    let nbEnemiesOnSide = getRandomArbitrary(10, nbEnemies - 30);
    this.enemyTop(game,nbEnemiesOnSide);

    // nbEnemies -= nbEnemiesOnSide;
    // nbEnemiesOnSide = getRandomArbitrary(10, nbEnemies - 20);
    // this.enemyLeft(game, nbEnemiesOnSide);

    // nbEnemies -= nbEnemiesOnSide;
    // nbEnemiesOnSide = getRandomArbitrary(10, nbEnemies - 10);
    // this.enemyBottom(game, nbEnemiesOnSide);

    // nbEnemies -= nbEnemiesOnSide;
    // this.enemyRight(game, nbEnemiesOnSide);

  }

  enemyBottom(game,nbEnemies) {

  }

  enemyTop(game, nbEnemies) {
    const elapsedX = (game.world.bounds.width - 2 * Border) / nbEnemies;
    for(let i = 0; i < nbEnemies; i++) {
      const randomY = getRandomArbitrary(0, Border - EnemyHeight);
      this.addEnemy(game, Border + elapsedX * i, randomY);
    }
  }

  enemyLeft(game, nbEnemies) {

  }

  enemyRight(game, nbEnemies) {

  }

  addEnemy(game, x, y) {
    const enemy = new Enemy(game,x, y);
    this.add(enemy);
  }

}

export default EnemyGroup;<commit_msg>fallow player<commit_after>import { EnemyWidth, EnemyHeight, Border } from "../Constants.js";
import { getRandomArbitrary } from "../utils";

import Enemy from "objects/Enemy";

class EnemyGroup extends Phaser.Group {

  constructor(game, parent, name) {
    super(game, parent, name, false, true, Phaser.Physics.ARCADE);
    let nbEnemies = getRandomArbitrary(40,50);

    let nbEnemiesOnSide = getRandomArbitrary(10, nbEnemies - 30);
    this.enemyTop(game,nbEnemiesOnSide);

    // nbEnemies -= nbEnemiesOnSide;
    // nbEnemiesOnSide = getRandomArbitrary(10, nbEnemies - 20);
    // this.enemyLeft(game, nbEnemiesOnSide);

     //nbEnemies -= nbEnemiesOnSide;
     //nbEnemiesOnSide = getRandomArbitrary(10, nbEnemies - 10);
     //this.enemyBottom(game, nbEnemiesOnSide);

    // nbEnemies -= nbEnemiesOnSide;
    // this.enemyRight(game, nbEnemiesOnSide);

  }

  getElapsedX(game, nbEnemies) {
    return (game.world.bounds.width - 2 * Border) / nbEnemies;
  }

  enemyBottom(game,nbEnemies) {
    const elapsedX = this.getElapsedX(game, nbEnemies);
    for(let i = 0; i < nbEnemies; i++) {
      const randomY = getRandomArbitrary(game.world.bounds.height - Border, game.world.bounds.height - EnemyHeight);
      this.addEnemy(game, Border + elapsedX * i, randomY);
    }
  }

  enemyTop(game, nbEnemies) {
    const elapsedX = this.getElapsedX(game, nbEnemies);
    for(let i = 0; i < nbEnemies; i++) {
      const randomY = getRandomArbitrary(0, Border - EnemyHeight);
      this.addEnemy(game, Border + elapsedX * i, randomY);
    }
  }

  enemyLeft(game, nbEnemies) {

  }

  enemyRight(game, nbEnemies) {

  }

  addEnemy(game, x, y) {
    const enemy = new Enemy(game,x, y);
    this.add(enemy);
  }

  follow(playerPosition) {
    this.children.forEach(enemy => {
      enemy.follow(playerPosition);
    });
  }

}

export default EnemyGroup;<|endoftext|>


<commit_before>// FIXME factor out key precondition (shift et. al)

goog.provide('ol.Control');

goog.require('ol.MapBrowserEvent');
goog.require('ol.control.Constraints');

/**
 * @constructor
 * @param {ol.control.Constraints} constraints Constraints.
 */
ol.Control = function(constraints) {

  /**
   * @protected
   * @type {ol.control.Constraints}
   */
  this.constraints = constraints;

};

/**
 * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event.
 */
ol.Control.prototype.handleMapBrowserEvent = goog.abstractMethod;

/**
 * @param {ol.Map} map Map.
 * @param {ol.Extent} extent Extent.
 */
ol.Control.prototype.fitExtent = function(map, extent) {
  var resolution = map.getResolutionForExtent(extent);
  resolution = this.constraints.resolution(resolution, 0);
  var center = extent.getCenter();
  center = this.constraints.center(center, resolution, ol.Coordinate.ZERO);
  map.withFrozenRendering(function() {
    map.setCenter(center);
    map.setResolution(resolution);
  });
};

/**
 * @param {ol.Map} map Map.
 * @param {ol.Coordinate} delta Delta.
 * @param {ol.Coordinate=} opt_anchor Anchor.
 */
ol.Control.prototype.pan = function(map, delta, opt_anchor) {
  var center = opt_anchor ? opt_anchor : map.getCenter();
  var resolution = map.getResolution();
  center = this.constraints.center(center, resolution, delta);
  map.setCenter(center);
};

/**
 * @param {ol.Map} map Map.
 * @param {number|undefined} rotation Rotation.
 * @param {number} delta Delta.
 * @param {ol.Coordinate=} opt_anchor Anchor.
 */
ol.Control.prototype.rotate = function(map, rotation, delta, opt_anchor) {
  // FIXME handle rotation about anchor
  rotation = this.constraints.rotation(rotation, delta);
  map.setRotation(rotation);
};

/**
 * @param {ol.Map} map Map.
 * @param {number|undefined} resolution Resolution.
 */
ol.Control.prototype.setResolution = function(map, resolution) {
  resolution = this.constraints.resolution(resolution, 0);
  map.setResolution(resolution);
};

/**
 * @param {ol.Map} map Map.
 * @param {number|undefined} resolution Resolution.
 * @param {number} delta Delta.
 * @param {ol.Coordinate=} opt_anchor Anchor.
 */
ol.Control.prototype.zoom = function(map, resolution, delta, opt_anchor) {
  if (goog.isDefAndNotNull(opt_anchor)) {
    var anchor = opt_anchor;
    var mapCenter = /** @type {!ol.Coordinate} */ map.getCenter();
    var mapResolution = map.getResolution();
    resolution = this.constraints.resolution(resolution, delta);
    var x = anchor.x - resolution *  (anchor.x - mapCenter.x) / mapResolution;
    var y = anchor.y - resolution *  (anchor.y - mapCenter.y) / mapResolution;
    var center = new ol.Coordinate(x, y);
    center = this.constraints.center(center, resolution, ol.Coordinate.ZERO);
    map.withFrozenRendering(function() {
      map.setCenter(center);
      map.setResolution(resolution);
    });
  } else {
    resolution = this.constraints.resolution(resolution, delta);
    map.setResolution(resolution);
  }
};
<commit_msg>Clean up whitespace<commit_after>// FIXME factor out key precondition (shift et. al)

goog.provide('ol.Control');

goog.require('ol.MapBrowserEvent');
goog.require('ol.control.Constraints');

/**
 * @constructor
 * @param {ol.control.Constraints} constraints Constraints.
 */
ol.Control = function(constraints) {

  /**
   * @protected
   * @type {ol.control.Constraints}
   */
  this.constraints = constraints;

};

/**
 * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event.
 */
ol.Control.prototype.handleMapBrowserEvent = goog.abstractMethod;

/**
 * @param {ol.Map} map Map.
 * @param {ol.Extent} extent Extent.
 */
ol.Control.prototype.fitExtent = function(map, extent) {
  var resolution = map.getResolutionForExtent(extent);
  resolution = this.constraints.resolution(resolution, 0);
  var center = extent.getCenter();
  center = this.constraints.center(center, resolution, ol.Coordinate.ZERO);
  map.withFrozenRendering(function() {
    map.setCenter(center);
    map.setResolution(resolution);
  });
};

/**
 * @param {ol.Map} map Map.
 * @param {ol.Coordinate} delta Delta.
 * @param {ol.Coordinate=} opt_anchor Anchor.
 */
ol.Control.prototype.pan = function(map, delta, opt_anchor) {
  var center = opt_anchor ? opt_anchor : map.getCenter();
  var resolution = map.getResolution();
  center = this.constraints.center(center, resolution, delta);
  map.setCenter(center);
};

/**
 * @param {ol.Map} map Map.
 * @param {number|undefined} rotation Rotation.
 * @param {number} delta Delta.
 * @param {ol.Coordinate=} opt_anchor Anchor.
 */
ol.Control.prototype.rotate = function(map, rotation, delta, opt_anchor) {
  // FIXME handle rotation about anchor
  rotation = this.constraints.rotation(rotation, delta);
  map.setRotation(rotation);
};

/**
 * @param {ol.Map} map Map.
 * @param {number|undefined} resolution Resolution.
 */
ol.Control.prototype.setResolution = function(map, resolution) {
  resolution = this.constraints.resolution(resolution, 0);
  map.setResolution(resolution);
};

/**
 * @param {ol.Map} map Map.
 * @param {number|undefined} resolution Resolution.
 * @param {number} delta Delta.
 * @param {ol.Coordinate=} opt_anchor Anchor.
 */
ol.Control.prototype.zoom = function(map, resolution, delta, opt_anchor) {
  if (goog.isDefAndNotNull(opt_anchor)) {
    var anchor = opt_anchor;
    var mapCenter = /** @type {!ol.Coordinate} */ map.getCenter();
    var mapResolution = map.getResolution();
    resolution = this.constraints.resolution(resolution, delta);
    var x = anchor.x - resolution * (anchor.x - mapCenter.x) / mapResolution;
    var y = anchor.y - resolution * (anchor.y - mapCenter.y) / mapResolution;
    var center = new ol.Coordinate(x, y);
    center = this.constraints.center(center, resolution, ol.Coordinate.ZERO);
    map.withFrozenRendering(function() {
      map.setCenter(center);
      map.setResolution(resolution);
    });
  } else {
    resolution = this.constraints.resolution(resolution, delta);
    map.setResolution(resolution);
  }
};
<|endoftext|>


<commit_before>/* ***** BEGIN LICENSE BLOCK *****
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (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.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is Ajax.org Code Editor (ACE).
 *
 * The Initial Developer of the Original Code is
 * Ajax.org B.V.
 * Portions created by the Initial Developer are Copyright (C) 2010
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s):
 *      Fabian Jakobs <fabian AT ajax DOT org>
 *
 * Alternatively, the contents of this file may be used under the terms of
 * either the GNU General Public License Version 2 or later (the "GPL"), or
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 * in which case the provisions of the GPL or the LGPL are applicable instead
 * of those above. If you wish to allow use of your version of this file only
 * under the terms of either the GPL or the LGPL, and not to allow others to
 * use your version of this file under the terms of the MPL, indicate your
 * decision by deleting the provisions above and replace them with the notice
 * and other provisions required by the GPL or the LGPL. If you do not delete
 * the provisions above, a recipient may use your version of this file under
 * the terms of any one of the MPL, the GPL or the LGPL.
 *
 * ***** END LICENSE BLOCK ***** */

define(function(require, exports, module) {

exports.cssClass = "ace-chrome";
exports.cssText = ".ace-chrome .ace_editor {\
  border: 2px solid rgb(159, 159, 159);\
}\
\
.ace-chrome .ace_editor.ace_focus {\
  border: 2px solid #327fbd;\
}\
\
.ace-chrome .ace_gutter {\
  width: 50px;\
  background: #e8e8e8;\
  color: #333;\
  overflow : hidden;\
}\
\
.ace-chrome .ace_gutter-layer {\
  width: 100%;\
  text-align: right;\
}\
\
.ace-chrome .ace_gutter-layer .ace_gutter-cell {\
  padding-right: 6px;\
}\
\
.ace-chrome .ace_print_margin {\
  width: 1px;\
  background: #e8e8e8;\
}\
\
.ace-chrome .ace_text-layer {\
  cursor: text;\
}\
\
.ace-chrome .ace_cursor {\
  border-left: 2px solid black;\
}\
\
.ace-chrome .ace_cursor.ace_overwrite {\
  border-left: 0px;\
  border-bottom: 1px solid black;\
}\
\
.ace-chrome .ace_line .ace_invisible {\
  color: rgb(191, 191, 191);\
}\
\
.ace-chrome .ace_line .ace_constant.ace_buildin {\
  color: rgb(88, 72, 246);\
}\
\
.ace-chrome .ace_line .ace_constant.ace_language {\
  color: rgb(88, 92, 246);\
}\
\
.ace-chrome .ace_line .ace_constant.ace_library {\
  color: rgb(6, 150, 14);\
}\
\
.ace-chrome .ace_line .ace_invalid {\
  background-color: rgb(153, 0, 0);\
  color: white;\
}\
\
.ace-chrome .ace_line .ace_fold {\
}\
\
.ace-chrome .ace_line .ace_support.ace_function {\
  color: rgb(60, 76, 114);\
}\
\
.ace-chrome .ace_line .ace_support.ace_constant {\
  color: rgb(6, 150, 14);\
}\
\
.ace-chrome .ace_line .ace_support.ace_type,\
.ace-chrome .ace_line .ace_support.ace_class {\
  color: rgb(109, 121, 222);\
}\
\
.ace-chrome .ace_variable.ace_parameter {\
  font-style:italic;\
color:#FD971F;\
}\
.ace-chrome .ace_line .ace_keyword.ace_operator {\
  color: rgb(104, 118, 135);\
}\
\
.ace-chrome .ace_line .ace_comment {\
  color: #236e24;\
}\
\
.ace-chrome .ace_line .ace_comment.ace_doc {\
  color: #236e24;\
}\
\
.ace-chrome .ace_line .ace_comment.ace_doc.ace_tag {\
  color: #236e24;\
}\
\
.ace-chrome .ace_line .ace_constant.ace_numeric {\
  color: rgb(0, 0, 205);\
}\
\
.ace-chrome .ace_line .ace_variable {\
  color: rgb(49, 132, 149);\
}\
\
.ace-chrome .ace_line .ace_xml_pe {\
  color: rgb(104, 104, 91);\
}\
\
.ace-chrome .ace_entity.ace_name.ace_function {\
  color: #0000A2;\
}\
\
.ace-chrome .ace_markup.ace_markupine {\
    text-decoration:underline;\
}\
\
.ace-chrome .ace_markup.ace_heading {\
  color: rgb(12, 7, 255);\
}\
\
.ace-chrome .ace_markup.ace_list {\
  color:rgb(185, 6, 144);\
}\
\
.ace-chrome .ace_marker-layer .ace_selection {\
  background: rgb(181, 213, 255);\
}\
\
.ace-chrome .ace_marker-layer .ace_step {\
  background: rgb(252, 255, 0);\
}\
\
.ace-chrome .ace_marker-layer .ace_stack {\
  background: rgb(164, 229, 101);\
}\
\
.ace-chrome .ace_marker-layer .ace_bracket {\
  margin: -1px 0 0 -1px;\
  border: 1px solid rgb(192, 192, 192);\
}\
\
.ace-chrome .ace_marker-layer .ace_active_line {\
  background: rgba(0, 0, 0, 0.07);\
}\
\
.ace-chrome .ace_marker-layer .ace_selected_word {\
  background: rgb(250, 250, 255);\
  border: 1px solid rgb(200, 200, 250);\
}\
\
.ace-chrome .ace_storage,\
.ace-chrome .ace_line .ace_keyword,\
.ace-chrome .ace_meta.ace_tag {\
  color: rgb(147, 15, 128);\
}\
\
.ace-chrome .ace_string.ace_regex {\
  color: rgb(255, 0, 0)\
}\
\
.ace-chrome .ace_line .ace_string,\
.ace-chrome .ace_entity.ace_other.ace_attribute-name{\
  color: #994409;\
}";

var dom = require("../lib/dom");
dom.importCssString(exports.cssText, exports.cssClass);

});
<commit_msg>Two minor fixes of gutter style<commit_after>/* ***** BEGIN LICENSE BLOCK *****
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (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.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is Ajax.org Code Editor (ACE).
 *
 * The Initial Developer of the Original Code is
 * Ajax.org B.V.
 * Portions created by the Initial Developer are Copyright (C) 2010
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s):
 *      Fabian Jakobs <fabian AT ajax DOT org>
 *
 * Alternatively, the contents of this file may be used under the terms of
 * either the GNU General Public License Version 2 or later (the "GPL"), or
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 * in which case the provisions of the GPL or the LGPL are applicable instead
 * of those above. If you wish to allow use of your version of this file only
 * under the terms of either the GPL or the LGPL, and not to allow others to
 * use your version of this file under the terms of the MPL, indicate your
 * decision by deleting the provisions above and replace them with the notice
 * and other provisions required by the GPL or the LGPL. If you do not delete
 * the provisions above, a recipient may use your version of this file under
 * the terms of any one of the MPL, the GPL or the LGPL.
 *
 * ***** END LICENSE BLOCK ***** */

define(function(require, exports, module) {

exports.cssClass = "ace-chrome";
exports.cssText = ".ace-chrome .ace_editor {\
  border: 2px solid rgb(159, 159, 159);\
}\
\
.ace-chrome .ace_editor.ace_focus {\
  border: 2px solid #327fbd;\
}\
\
.ace-chrome .ace_gutter {\
  background: #e8e8e8;\
  color: #333;\
  overflow : hidden;\
}\
\
.ace-chrome .ace_gutter-layer {\
  width: 100%;\
  text-align: right;\
}\
\
.ace-chrome .ace_print_margin {\
  width: 1px;\
  background: #e8e8e8;\
}\
\
.ace-chrome .ace_text-layer {\
  cursor: text;\
}\
\
.ace-chrome .ace_cursor {\
  border-left: 2px solid black;\
}\
\
.ace-chrome .ace_cursor.ace_overwrite {\
  border-left: 0px;\
  border-bottom: 1px solid black;\
}\
\
.ace-chrome .ace_line .ace_invisible {\
  color: rgb(191, 191, 191);\
}\
\
.ace-chrome .ace_line .ace_constant.ace_buildin {\
  color: rgb(88, 72, 246);\
}\
\
.ace-chrome .ace_line .ace_constant.ace_language {\
  color: rgb(88, 92, 246);\
}\
\
.ace-chrome .ace_line .ace_constant.ace_library {\
  color: rgb(6, 150, 14);\
}\
\
.ace-chrome .ace_line .ace_invalid {\
  background-color: rgb(153, 0, 0);\
  color: white;\
}\
\
.ace-chrome .ace_line .ace_fold {\
}\
\
.ace-chrome .ace_line .ace_support.ace_function {\
  color: rgb(60, 76, 114);\
}\
\
.ace-chrome .ace_line .ace_support.ace_constant {\
  color: rgb(6, 150, 14);\
}\
\
.ace-chrome .ace_line .ace_support.ace_type,\
.ace-chrome .ace_line .ace_support.ace_class {\
  color: rgb(109, 121, 222);\
}\
\
.ace-chrome .ace_variable.ace_parameter {\
  font-style:italic;\
color:#FD971F;\
}\
.ace-chrome .ace_line .ace_keyword.ace_operator {\
  color: rgb(104, 118, 135);\
}\
\
.ace-chrome .ace_line .ace_comment {\
  color: #236e24;\
}\
\
.ace-chrome .ace_line .ace_comment.ace_doc {\
  color: #236e24;\
}\
\
.ace-chrome .ace_line .ace_comment.ace_doc.ace_tag {\
  color: #236e24;\
}\
\
.ace-chrome .ace_line .ace_constant.ace_numeric {\
  color: rgb(0, 0, 205);\
}\
\
.ace-chrome .ace_line .ace_variable {\
  color: rgb(49, 132, 149);\
}\
\
.ace-chrome .ace_line .ace_xml_pe {\
  color: rgb(104, 104, 91);\
}\
\
.ace-chrome .ace_entity.ace_name.ace_function {\
  color: #0000A2;\
}\
\
.ace-chrome .ace_markup.ace_markupine {\
    text-decoration:underline;\
}\
\
.ace-chrome .ace_markup.ace_heading {\
  color: rgb(12, 7, 255);\
}\
\
.ace-chrome .ace_markup.ace_list {\
  color:rgb(185, 6, 144);\
}\
\
.ace-chrome .ace_marker-layer .ace_selection {\
  background: rgb(181, 213, 255);\
}\
\
.ace-chrome .ace_marker-layer .ace_step {\
  background: rgb(252, 255, 0);\
}\
\
.ace-chrome .ace_marker-layer .ace_stack {\
  background: rgb(164, 229, 101);\
}\
\
.ace-chrome .ace_marker-layer .ace_bracket {\
  margin: -1px 0 0 -1px;\
  border: 1px solid rgb(192, 192, 192);\
}\
\
.ace-chrome .ace_marker-layer .ace_active_line {\
  background: rgba(0, 0, 0, 0.07);\
}\
\
.ace-chrome .ace_marker-layer .ace_selected_word {\
  background: rgb(250, 250, 255);\
  border: 1px solid rgb(200, 200, 250);\
}\
\
.ace-chrome .ace_storage,\
.ace-chrome .ace_line .ace_keyword,\
.ace-chrome .ace_meta.ace_tag {\
  color: rgb(147, 15, 128);\
}\
\
.ace-chrome .ace_string.ace_regex {\
  color: rgb(255, 0, 0)\
}\
\
.ace-chrome .ace_line .ace_string,\
.ace-chrome .ace_entity.ace_other.ace_attribute-name{\
  color: #994409;\
}";

var dom = require("../lib/dom");
dom.importCssString(exports.cssText, exports.cssClass);

});
<|endoftext|>


<commit_before>/**
 * @module ol/format/IIIFInfo
 */

import {assert} from '../asserts.js';

/**
 * @typedef {Object} PreferredOptions
 * @property {string} [format] Preferred image format. Will be used if the image information
 * indicates support for that format.
 * @property {string} [quality] IIIF image qualitiy.  Will be used if the image information
 * indicates support for that quality.
 */

/**
 * @typedef {Object} SupportedFeatures
 * @property {Array<string>} [supports] Supported IIIF image size and region
 * calculation features.
 * @property {Array<string>} [formats] Supported image formats.
 * @property {Array<string>} [qualities] Supported IIIF image qualities.
 */

/**
 * @typedef {Object} TileInfo
 * @property {Array<number>} scaleFactors Supported resolution scaling factors.
 * @property {number} width Tile width in pixels.
 * @property {number} [height] Tile height in pixels. Same as tile width if height is
 * not given.
 */

/**
 * @typedef {Object} IiifProfile
 * @property {Array<string>} [formats] Supported image formats for the image service.
 * @property {Array<string>} [qualities] Supported IIIF image qualities.
 * @property {Array<string>} [supports] Supported features.
 * @property {number} [maxArea] Maximum area (pixels) available for this image service.
 * @property {number} [maxHeight] Maximum height.
 * @property {number} [maxWidth] Maximum width.
 */

/**
 * @typedef {Object<string,string|number|Array<number|string|IiifProfile>|Object<string, number>|TileInfo>}
 *    ImageInformationResponse
 */

/**
 * Enum representing the major IIIF Image API versions
 * @enum {string}
 */
const Versions = {
  VERSION1: 'version1',
  VERSION2: 'version2',
  VERSION3: 'version3',
};

/**
 * Supported image formats, qualities and supported region / size calculation features
 * for different image API versions and compliance levels
 * @const
 * @type {Object<string, Object<string, SupportedFeatures>>}
 */
const IIIF_PROFILE_VALUES = {};
IIIF_PROFILE_VALUES[Versions.VERSION1] = {
  'level0': {
    supports: [],
    formats: [],
    qualities: ['native'],
  },
  'level1': {
    supports: ['regionByPx', 'sizeByW', 'sizeByH', 'sizeByPct'],
    formats: ['jpg'],
    qualities: ['native'],
  },
  'level2': {
    supports: [
      'regionByPx',
      'regionByPct',
      'sizeByW',
      'sizeByH',
      'sizeByPct',
      'sizeByConfinedWh',
      'sizeByWh',
    ],
    formats: ['jpg', 'png'],
    qualities: ['native', 'color', 'grey', 'bitonal'],
  },
};
IIIF_PROFILE_VALUES[Versions.VERSION2] = {
  'level0': {
    supports: [],
    formats: ['jpg'],
    qualities: ['default'],
  },
  'level1': {
    supports: ['regionByPx', 'sizeByW', 'sizeByH', 'sizeByPct'],
    formats: ['jpg'],
    qualities: ['default'],
  },
  'level2': {
    supports: [
      'regionByPx',
      'regionByPct',
      'sizeByW',
      'sizeByH',
      'sizeByPct',
      'sizeByConfinedWh',
      'sizeByDistortedWh',
      'sizeByWh',
    ],
    formats: ['jpg', 'png'],
    qualities: ['default', 'bitonal'],
  },
};
IIIF_PROFILE_VALUES[Versions.VERSION3] = {
  'level0': {
    supports: [],
    formats: ['jpg'],
    qualities: ['default'],
  },
  'level1': {
    supports: ['regionByPx', 'regionSquare', 'sizeByW', 'sizeByH', 'sizeByWh'],
    formats: ['jpg'],
    qualities: ['default'],
  },
  'level2': {
    supports: [
      'regionByPx',
      'regionSquare',
      'regionByPct',
      'sizeByW',
      'sizeByH',
      'sizeByPct',
      'sizeByConfinedWh',
      'sizeByWh',
    ],
    formats: ['jpg', 'png'],
    qualities: ['default'],
  },
};
IIIF_PROFILE_VALUES['none'] = {
  'none': {
    supports: [],
    formats: [],
    qualities: [],
  },
};

const COMPLIANCE_VERSION1 = new RegExp(
  '^https?://library.stanford.edu/iiif/image-api/(1.1/)?compliance.html#level[0-2]$'
);
const COMPLIANCE_VERSION2 = new RegExp(
  '^https?://iiif.io/api/image/2/level[0-2](.json)?$'
);
const COMPLIANCE_VERSION3 = new RegExp(
  '(^https?://iiif.io/api/image/3/level[0-2](.json)?$)|(^level[0-2]$)'
);

function generateVersion1Options(iiifInfo) {
  let levelProfile = iiifInfo.getComplianceLevelSupportedFeatures();
  // Version 1.0 and 1.1 do not require a profile.
  if (levelProfile === undefined) {
    levelProfile = IIIF_PROFILE_VALUES[Versions.VERSION1]['level0'];
  }
  return {
    url:
      iiifInfo.imageInfo['@id'] === undefined
        ? undefined
        : iiifInfo.imageInfo['@id'].replace(/\/?(info.json)?$/g, ''),
    supports: levelProfile.supports,
    formats: [
      ...levelProfile.formats,
      iiifInfo.imageInfo.formats === undefined
        ? []
        : iiifInfo.imageInfo.formats,
    ],
    qualities: [
      ...levelProfile.qualities,
      iiifInfo.imageInfo.qualities === undefined
        ? []
        : iiifInfo.imageInfo.qualities,
    ],
    resolutions: iiifInfo.imageInfo.scale_factors,
    tileSize:
      iiifInfo.imageInfo.tile_width !== undefined
        ? iiifInfo.imageInfo.tile_height !== undefined
          ? [iiifInfo.imageInfo.tile_width, iiifInfo.imageInfo.tile_height]
          : [iiifInfo.imageInfo.tile_width, iiifInfo.imageInfo.tile_width]
        : iiifInfo.imageInfo.tile_height != undefined
        ? [iiifInfo.imageInfo.tile_height, iiifInfo.imageInfo.tile_height]
        : undefined,
  };
}

function generateVersion2Options(iiifInfo) {
  const levelProfile = iiifInfo.getComplianceLevelSupportedFeatures(),
    additionalProfile =
      Array.isArray(iiifInfo.imageInfo.profile) &&
      iiifInfo.imageInfo.profile.length > 1,
    profileSupports =
      additionalProfile && iiifInfo.imageInfo.profile[1].supports
        ? iiifInfo.imageInfo.profile[1].supports
        : [],
    profileFormats =
      additionalProfile && iiifInfo.imageInfo.profile[1].formats
        ? iiifInfo.imageInfo.profile[1].formats
        : [],
    profileQualities =
      additionalProfile && iiifInfo.imageInfo.profile[1].qualities
        ? iiifInfo.imageInfo.profile[1].qualities
        : [];
  return {
    url: iiifInfo.imageInfo['@id'].replace(/\/?(info.json)?$/g, ''),
    sizes:
      iiifInfo.imageInfo.sizes === undefined
        ? undefined
        : iiifInfo.imageInfo.sizes.map(function (size) {
            return [size.width, size.height];
          }),
    tileSize:
      iiifInfo.imageInfo.tiles === undefined
        ? undefined
        : [
            iiifInfo.imageInfo.tiles.map(function (tile) {
              return tile.width;
            })[0],
            iiifInfo.imageInfo.tiles.map(function (tile) {
              return tile.height === undefined ? tile.width : tile.height;
            })[0],
          ],
    resolutions:
      iiifInfo.imageInfo.tiles === undefined
        ? undefined
        : iiifInfo.imageInfo.tiles.map(function (tile) {
            return tile.scaleFactors;
          })[0],
    supports: [...levelProfile.supports, ...profileSupports],
    formats: [...levelProfile.formats, ...profileFormats],
    qualities: [...levelProfile.qualities, ...profileQualities],
  };
}

function generateVersion3Options(iiifInfo) {
  const levelProfile = iiifInfo.getComplianceLevelSupportedFeatures(),
    formats =
      iiifInfo.imageInfo.extraFormats === undefined
        ? levelProfile.formats
        : [...levelProfile.formats, ...iiifInfo.imageInfo.extraFormats],
    preferredFormat =
      iiifInfo.imageInfo.preferredFormats !== undefined &&
      Array.isArray(iiifInfo.imageInfo.preferredFormats) &&
      iiifInfo.imageInfo.preferredFormats.length > 0
        ? iiifInfo.imageInfo.preferredFormats
            .filter(function (format) {
              return ['jpg', 'png', 'gif'].includes(format);
            })
            .reduce(function (acc, format) {
              return acc === undefined && formats.includes(format)
                ? format
                : acc;
            }, undefined)
        : undefined;
  return {
    url: iiifInfo.imageInfo['id'],
    sizes:
      iiifInfo.imageInfo.sizes === undefined
        ? undefined
        : iiifInfo.imageInfo.sizes.map(function (size) {
            return [size.width, size.height];
          }),
    tileSize:
      iiifInfo.imageInfo.tiles === undefined
        ? undefined
        : [
            iiifInfo.imageInfo.tiles.map(function (tile) {
              return tile.width;
            })[0],
            iiifInfo.imageInfo.tiles.map(function (tile) {
              return tile.height;
            })[0],
          ],
    resolutions:
      iiifInfo.imageInfo.tiles === undefined
        ? undefined
        : iiifInfo.imageInfo.tiles.map(function (tile) {
            return tile.scaleFactors;
          })[0],
    supports:
      iiifInfo.imageInfo.extraFeatures === undefined
        ? levelProfile.supports
        : [...levelProfile.supports, ...iiifInfo.imageInfo.extraFeatures],
    formats: formats,
    qualities:
      iiifInfo.imageInfo.extraQualities === undefined
        ? levelProfile.qualities
        : [...levelProfile.qualities, ...iiifInfo.imageInfo.extraQualities],
    preferredFormat: preferredFormat,
  };
}

const versionFunctions = {};
versionFunctions[Versions.VERSION1] = generateVersion1Options;
versionFunctions[Versions.VERSION2] = generateVersion2Options;
versionFunctions[Versions.VERSION3] = generateVersion3Options;

/**
 * @classdesc
 * Format for transforming IIIF Image API image information responses into
 * IIIF tile source ready options
 *
 * @api
 */
class IIIFInfo {
  /**
   * @param {string|ImageInformationResponse} imageInfo
   * Deserialized image information JSON response object or JSON response as string
   */
  constructor(imageInfo) {
    this.setImageInfo(imageInfo);
  }

  /**
   * @param {string|ImageInformationResponse} imageInfo
   * Deserialized image information JSON response object or JSON response as string
   * @api
   */
  setImageInfo(imageInfo) {
    if (typeof imageInfo == 'string') {
      this.imageInfo = JSON.parse(imageInfo);
    } else {
      this.imageInfo = imageInfo;
    }
  }

  /**
   * @returns {Versions} Major IIIF version.
   * @api
   */
  getImageApiVersion() {
    if (this.imageInfo === undefined) {
      return;
    }
    let context = this.imageInfo['@context'] || 'ol-no-context';
    if (typeof context == 'string') {
      context = [context];
    }
    for (let i = 0; i < context.length; i++) {
      switch (context[i]) {
        case 'http://library.stanford.edu/iiif/image-api/1.1/context.json':
        case 'http://iiif.io/api/image/1/context.json':
          return Versions.VERSION1;
        case 'http://iiif.io/api/image/2/context.json':
          return Versions.VERSION2;
        case 'http://iiif.io/api/image/3/context.json':
          return Versions.VERSION3;
        case 'ol-no-context':
          // Image API 1.0 has no '@context'
          if (
            this.getComplianceLevelEntryFromProfile(Versions.VERSION1) &&
            this.imageInfo.identifier
          ) {
            return Versions.VERSION1;
          }
          break;
        default:
      }
    }
    assert(false, 61);
  }

  /**
   * @param {Versions} version Optional IIIF image API version
   * @returns {string} Compliance level as it appears in the IIIF image information
   * response.
   */
  getComplianceLevelEntryFromProfile(version) {
    if (this.imageInfo === undefined || this.imageInfo.profile === undefined) {
      return;
    }
    if (version === undefined) {
      version = this.getImageApiVersion();
    }
    switch (version) {
      case Versions.VERSION1:
        if (COMPLIANCE_VERSION1.test(this.imageInfo.profile)) {
          return this.imageInfo.profile;
        }
        break;
      case Versions.VERSION3:
        if (COMPLIANCE_VERSION3.test(this.imageInfo.profile)) {
          return this.imageInfo.profile;
        }
        break;
      case Versions.VERSION2:
        if (
          typeof this.imageInfo.profile === 'string' &&
          COMPLIANCE_VERSION2.test(this.imageInfo.profile)
        ) {
          return this.imageInfo.profile;
        }
        if (
          Array.isArray(this.imageInfo.profile) &&
          this.imageInfo.profile.length > 0 &&
          typeof this.imageInfo.profile[0] === 'string' &&
          COMPLIANCE_VERSION2.test(this.imageInfo.profile[0])
        ) {
          return this.imageInfo.profile[0];
        }
        break;
      default:
    }
  }

  /**
   * @param {Versions} version Optional IIIF image API version
   * @returns {string} Compliance level, on of 'level0', 'level1' or 'level2' or undefined
   */
  getComplianceLevelFromProfile(version) {
    const complianceLevel = this.getComplianceLevelEntryFromProfile(version);
    if (complianceLevel === undefined) {
      return undefined;
    }
    const level = complianceLevel.match(/level[0-2](\.json)?$/g);
    return Array.isArray(level) ? level[0].replace('.json', '') : undefined;
  }

  /**
   * @returns {SupportedFeatures} Image formats, qualities and region / size calculation
   * methods that are supported by the IIIF service.
   */
  getComplianceLevelSupportedFeatures() {
    if (this.imageInfo === undefined) {
      return;
    }
    const version = this.getImageApiVersion();
    const level = this.getComplianceLevelFromProfile(version);
    if (level === undefined) {
      return IIIF_PROFILE_VALUES['none']['none'];
    }
    return IIIF_PROFILE_VALUES[version][level];
  }

  /**
   * @param {PreferredOptions=} opt_preferredOptions Optional options for preferred format and quality.
   * @returns {import("../source/IIIF.js").Options} IIIF tile source ready constructor options.
   * @api
   */
  getTileSourceOptions(opt_preferredOptions) {
    const options = opt_preferredOptions || {},
      version = this.getImageApiVersion();
    if (version === undefined) {
      return;
    }
    const imageOptions =
      version === undefined ? undefined : versionFunctions[version](this);
    if (imageOptions === undefined) {
      return;
    }
    return {
      url: imageOptions.url,
      version: version,
      size: [this.imageInfo.width, this.imageInfo.height],
      sizes: imageOptions.sizes,
      format:
        options.format !== undefined &&
        imageOptions.formats.includes(options.format)
          ? options.format
          : imageOptions.preferredFormat !== undefined
          ? imageOptions.preferredFormat
          : 'jpg',
      supports: imageOptions.supports,
      quality:
        options.quality && imageOptions.qualities.includes(options.quality)
          ? options.quality
          : imageOptions.qualities.includes('native')
          ? 'native'
          : 'default',
      resolutions: Array.isArray(imageOptions.resolutions)
        ? imageOptions.resolutions.sort(function (a, b) {
            return b - a;
          })
        : undefined,
      tileSize: imageOptions.tileSize,
    };
  }
}

export default IIIFInfo;
export {Versions};
<commit_msg>Properly export enum<commit_after>/**
 * @module ol/format/IIIFInfo
 */

import {assert} from '../asserts.js';

/**
 * @typedef {Object} PreferredOptions
 * @property {string} [format] Preferred image format. Will be used if the image information
 * indicates support for that format.
 * @property {string} [quality] IIIF image qualitiy.  Will be used if the image information
 * indicates support for that quality.
 */

/**
 * @typedef {Object} SupportedFeatures
 * @property {Array<string>} [supports] Supported IIIF image size and region
 * calculation features.
 * @property {Array<string>} [formats] Supported image formats.
 * @property {Array<string>} [qualities] Supported IIIF image qualities.
 */

/**
 * @typedef {Object} TileInfo
 * @property {Array<number>} scaleFactors Supported resolution scaling factors.
 * @property {number} width Tile width in pixels.
 * @property {number} [height] Tile height in pixels. Same as tile width if height is
 * not given.
 */

/**
 * @typedef {Object} IiifProfile
 * @property {Array<string>} [formats] Supported image formats for the image service.
 * @property {Array<string>} [qualities] Supported IIIF image qualities.
 * @property {Array<string>} [supports] Supported features.
 * @property {number} [maxArea] Maximum area (pixels) available for this image service.
 * @property {number} [maxHeight] Maximum height.
 * @property {number} [maxWidth] Maximum width.
 */

/**
 * @typedef {Object<string,string|number|Array<number|string|IiifProfile>|Object<string, number>|TileInfo>}
 *    ImageInformationResponse
 */

/**
 * Enum representing the major IIIF Image API versions
 * @enum {string}
 */
export const Versions = {
  VERSION1: 'version1',
  VERSION2: 'version2',
  VERSION3: 'version3',
};

/**
 * Supported image formats, qualities and supported region / size calculation features
 * for different image API versions and compliance levels
 * @const
 * @type {Object<string, Object<string, SupportedFeatures>>}
 */
const IIIF_PROFILE_VALUES = {};
IIIF_PROFILE_VALUES[Versions.VERSION1] = {
  'level0': {
    supports: [],
    formats: [],
    qualities: ['native'],
  },
  'level1': {
    supports: ['regionByPx', 'sizeByW', 'sizeByH', 'sizeByPct'],
    formats: ['jpg'],
    qualities: ['native'],
  },
  'level2': {
    supports: [
      'regionByPx',
      'regionByPct',
      'sizeByW',
      'sizeByH',
      'sizeByPct',
      'sizeByConfinedWh',
      'sizeByWh',
    ],
    formats: ['jpg', 'png'],
    qualities: ['native', 'color', 'grey', 'bitonal'],
  },
};
IIIF_PROFILE_VALUES[Versions.VERSION2] = {
  'level0': {
    supports: [],
    formats: ['jpg'],
    qualities: ['default'],
  },
  'level1': {
    supports: ['regionByPx', 'sizeByW', 'sizeByH', 'sizeByPct'],
    formats: ['jpg'],
    qualities: ['default'],
  },
  'level2': {
    supports: [
      'regionByPx',
      'regionByPct',
      'sizeByW',
      'sizeByH',
      'sizeByPct',
      'sizeByConfinedWh',
      'sizeByDistortedWh',
      'sizeByWh',
    ],
    formats: ['jpg', 'png'],
    qualities: ['default', 'bitonal'],
  },
};
IIIF_PROFILE_VALUES[Versions.VERSION3] = {
  'level0': {
    supports: [],
    formats: ['jpg'],
    qualities: ['default'],
  },
  'level1': {
    supports: ['regionByPx', 'regionSquare', 'sizeByW', 'sizeByH', 'sizeByWh'],
    formats: ['jpg'],
    qualities: ['default'],
  },
  'level2': {
    supports: [
      'regionByPx',
      'regionSquare',
      'regionByPct',
      'sizeByW',
      'sizeByH',
      'sizeByPct',
      'sizeByConfinedWh',
      'sizeByWh',
    ],
    formats: ['jpg', 'png'],
    qualities: ['default'],
  },
};
IIIF_PROFILE_VALUES['none'] = {
  'none': {
    supports: [],
    formats: [],
    qualities: [],
  },
};

const COMPLIANCE_VERSION1 = new RegExp(
  '^https?://library.stanford.edu/iiif/image-api/(1.1/)?compliance.html#level[0-2]$'
);
const COMPLIANCE_VERSION2 = new RegExp(
  '^https?://iiif.io/api/image/2/level[0-2](.json)?$'
);
const COMPLIANCE_VERSION3 = new RegExp(
  '(^https?://iiif.io/api/image/3/level[0-2](.json)?$)|(^level[0-2]$)'
);

function generateVersion1Options(iiifInfo) {
  let levelProfile = iiifInfo.getComplianceLevelSupportedFeatures();
  // Version 1.0 and 1.1 do not require a profile.
  if (levelProfile === undefined) {
    levelProfile = IIIF_PROFILE_VALUES[Versions.VERSION1]['level0'];
  }
  return {
    url:
      iiifInfo.imageInfo['@id'] === undefined
        ? undefined
        : iiifInfo.imageInfo['@id'].replace(/\/?(info.json)?$/g, ''),
    supports: levelProfile.supports,
    formats: [
      ...levelProfile.formats,
      iiifInfo.imageInfo.formats === undefined
        ? []
        : iiifInfo.imageInfo.formats,
    ],
    qualities: [
      ...levelProfile.qualities,
      iiifInfo.imageInfo.qualities === undefined
        ? []
        : iiifInfo.imageInfo.qualities,
    ],
    resolutions: iiifInfo.imageInfo.scale_factors,
    tileSize:
      iiifInfo.imageInfo.tile_width !== undefined
        ? iiifInfo.imageInfo.tile_height !== undefined
          ? [iiifInfo.imageInfo.tile_width, iiifInfo.imageInfo.tile_height]
          : [iiifInfo.imageInfo.tile_width, iiifInfo.imageInfo.tile_width]
        : iiifInfo.imageInfo.tile_height != undefined
        ? [iiifInfo.imageInfo.tile_height, iiifInfo.imageInfo.tile_height]
        : undefined,
  };
}

function generateVersion2Options(iiifInfo) {
  const levelProfile = iiifInfo.getComplianceLevelSupportedFeatures(),
    additionalProfile =
      Array.isArray(iiifInfo.imageInfo.profile) &&
      iiifInfo.imageInfo.profile.length > 1,
    profileSupports =
      additionalProfile && iiifInfo.imageInfo.profile[1].supports
        ? iiifInfo.imageInfo.profile[1].supports
        : [],
    profileFormats =
      additionalProfile && iiifInfo.imageInfo.profile[1].formats
        ? iiifInfo.imageInfo.profile[1].formats
        : [],
    profileQualities =
      additionalProfile && iiifInfo.imageInfo.profile[1].qualities
        ? iiifInfo.imageInfo.profile[1].qualities
        : [];
  return {
    url: iiifInfo.imageInfo['@id'].replace(/\/?(info.json)?$/g, ''),
    sizes:
      iiifInfo.imageInfo.sizes === undefined
        ? undefined
        : iiifInfo.imageInfo.sizes.map(function (size) {
            return [size.width, size.height];
          }),
    tileSize:
      iiifInfo.imageInfo.tiles === undefined
        ? undefined
        : [
            iiifInfo.imageInfo.tiles.map(function (tile) {
              return tile.width;
            })[0],
            iiifInfo.imageInfo.tiles.map(function (tile) {
              return tile.height === undefined ? tile.width : tile.height;
            })[0],
          ],
    resolutions:
      iiifInfo.imageInfo.tiles === undefined
        ? undefined
        : iiifInfo.imageInfo.tiles.map(function (tile) {
            return tile.scaleFactors;
          })[0],
    supports: [...levelProfile.supports, ...profileSupports],
    formats: [...levelProfile.formats, ...profileFormats],
    qualities: [...levelProfile.qualities, ...profileQualities],
  };
}

function generateVersion3Options(iiifInfo) {
  const levelProfile = iiifInfo.getComplianceLevelSupportedFeatures(),
    formats =
      iiifInfo.imageInfo.extraFormats === undefined
        ? levelProfile.formats
        : [...levelProfile.formats, ...iiifInfo.imageInfo.extraFormats],
    preferredFormat =
      iiifInfo.imageInfo.preferredFormats !== undefined &&
      Array.isArray(iiifInfo.imageInfo.preferredFormats) &&
      iiifInfo.imageInfo.preferredFormats.length > 0
        ? iiifInfo.imageInfo.preferredFormats
            .filter(function (format) {
              return ['jpg', 'png', 'gif'].includes(format);
            })
            .reduce(function (acc, format) {
              return acc === undefined && formats.includes(format)
                ? format
                : acc;
            }, undefined)
        : undefined;
  return {
    url: iiifInfo.imageInfo['id'],
    sizes:
      iiifInfo.imageInfo.sizes === undefined
        ? undefined
        : iiifInfo.imageInfo.sizes.map(function (size) {
            return [size.width, size.height];
          }),
    tileSize:
      iiifInfo.imageInfo.tiles === undefined
        ? undefined
        : [
            iiifInfo.imageInfo.tiles.map(function (tile) {
              return tile.width;
            })[0],
            iiifInfo.imageInfo.tiles.map(function (tile) {
              return tile.height;
            })[0],
          ],
    resolutions:
      iiifInfo.imageInfo.tiles === undefined
        ? undefined
        : iiifInfo.imageInfo.tiles.map(function (tile) {
            return tile.scaleFactors;
          })[0],
    supports:
      iiifInfo.imageInfo.extraFeatures === undefined
        ? levelProfile.supports
        : [...levelProfile.supports, ...iiifInfo.imageInfo.extraFeatures],
    formats: formats,
    qualities:
      iiifInfo.imageInfo.extraQualities === undefined
        ? levelProfile.qualities
        : [...levelProfile.qualities, ...iiifInfo.imageInfo.extraQualities],
    preferredFormat: preferredFormat,
  };
}

const versionFunctions = {};
versionFunctions[Versions.VERSION1] = generateVersion1Options;
versionFunctions[Versions.VERSION2] = generateVersion2Options;
versionFunctions[Versions.VERSION3] = generateVersion3Options;

/**
 * @classdesc
 * Format for transforming IIIF Image API image information responses into
 * IIIF tile source ready options
 *
 * @api
 */
class IIIFInfo {
  /**
   * @param {string|ImageInformationResponse} imageInfo
   * Deserialized image information JSON response object or JSON response as string
   */
  constructor(imageInfo) {
    this.setImageInfo(imageInfo);
  }

  /**
   * @param {string|ImageInformationResponse} imageInfo
   * Deserialized image information JSON response object or JSON response as string
   * @api
   */
  setImageInfo(imageInfo) {
    if (typeof imageInfo == 'string') {
      this.imageInfo = JSON.parse(imageInfo);
    } else {
      this.imageInfo = imageInfo;
    }
  }

  /**
   * @returns {Versions} Major IIIF version.
   * @api
   */
  getImageApiVersion() {
    if (this.imageInfo === undefined) {
      return;
    }
    let context = this.imageInfo['@context'] || 'ol-no-context';
    if (typeof context == 'string') {
      context = [context];
    }
    for (let i = 0; i < context.length; i++) {
      switch (context[i]) {
        case 'http://library.stanford.edu/iiif/image-api/1.1/context.json':
        case 'http://iiif.io/api/image/1/context.json':
          return Versions.VERSION1;
        case 'http://iiif.io/api/image/2/context.json':
          return Versions.VERSION2;
        case 'http://iiif.io/api/image/3/context.json':
          return Versions.VERSION3;
        case 'ol-no-context':
          // Image API 1.0 has no '@context'
          if (
            this.getComplianceLevelEntryFromProfile(Versions.VERSION1) &&
            this.imageInfo.identifier
          ) {
            return Versions.VERSION1;
          }
          break;
        default:
      }
    }
    assert(false, 61);
  }

  /**
   * @param {Versions} version Optional IIIF image API version
   * @returns {string} Compliance level as it appears in the IIIF image information
   * response.
   */
  getComplianceLevelEntryFromProfile(version) {
    if (this.imageInfo === undefined || this.imageInfo.profile === undefined) {
      return;
    }
    if (version === undefined) {
      version = this.getImageApiVersion();
    }
    switch (version) {
      case Versions.VERSION1:
        if (COMPLIANCE_VERSION1.test(this.imageInfo.profile)) {
          return this.imageInfo.profile;
        }
        break;
      case Versions.VERSION3:
        if (COMPLIANCE_VERSION3.test(this.imageInfo.profile)) {
          return this.imageInfo.profile;
        }
        break;
      case Versions.VERSION2:
        if (
          typeof this.imageInfo.profile === 'string' &&
          COMPLIANCE_VERSION2.test(this.imageInfo.profile)
        ) {
          return this.imageInfo.profile;
        }
        if (
          Array.isArray(this.imageInfo.profile) &&
          this.imageInfo.profile.length > 0 &&
          typeof this.imageInfo.profile[0] === 'string' &&
          COMPLIANCE_VERSION2.test(this.imageInfo.profile[0])
        ) {
          return this.imageInfo.profile[0];
        }
        break;
      default:
    }
  }

  /**
   * @param {Versions} version Optional IIIF image API version
   * @returns {string} Compliance level, on of 'level0', 'level1' or 'level2' or undefined
   */
  getComplianceLevelFromProfile(version) {
    const complianceLevel = this.getComplianceLevelEntryFromProfile(version);
    if (complianceLevel === undefined) {
      return undefined;
    }
    const level = complianceLevel.match(/level[0-2](\.json)?$/g);
    return Array.isArray(level) ? level[0].replace('.json', '') : undefined;
  }

  /**
   * @returns {SupportedFeatures} Image formats, qualities and region / size calculation
   * methods that are supported by the IIIF service.
   */
  getComplianceLevelSupportedFeatures() {
    if (this.imageInfo === undefined) {
      return;
    }
    const version = this.getImageApiVersion();
    const level = this.getComplianceLevelFromProfile(version);
    if (level === undefined) {
      return IIIF_PROFILE_VALUES['none']['none'];
    }
    return IIIF_PROFILE_VALUES[version][level];
  }

  /**
   * @param {PreferredOptions=} opt_preferredOptions Optional options for preferred format and quality.
   * @returns {import("../source/IIIF.js").Options} IIIF tile source ready constructor options.
   * @api
   */
  getTileSourceOptions(opt_preferredOptions) {
    const options = opt_preferredOptions || {},
      version = this.getImageApiVersion();
    if (version === undefined) {
      return;
    }
    const imageOptions =
      version === undefined ? undefined : versionFunctions[version](this);
    if (imageOptions === undefined) {
      return;
    }
    return {
      url: imageOptions.url,
      version: version,
      size: [this.imageInfo.width, this.imageInfo.height],
      sizes: imageOptions.sizes,
      format:
        options.format !== undefined &&
        imageOptions.formats.includes(options.format)
          ? options.format
          : imageOptions.preferredFormat !== undefined
          ? imageOptions.preferredFormat
          : 'jpg',
      supports: imageOptions.supports,
      quality:
        options.quality && imageOptions.qualities.includes(options.quality)
          ? options.quality
          : imageOptions.qualities.includes('native')
          ? 'native'
          : 'default',
      resolutions: Array.isArray(imageOptions.resolutions)
        ? imageOptions.resolutions.sort(function (a, b) {
            return b - a;
          })
        : undefined,
      tileSize: imageOptions.tileSize,
    };
  }
}

export default IIIFInfo;
<|endoftext|>


<commit_before>'use strict';
function NGAdapter(opt) {
    this.opt = opt || {};
    this.opt.name = opt.name || '_html_';
    this.contentParts = [];
    this.separator = new Buffer(opt.separator);
};

NGAdapter.prototype.getHeader = function () {
    return '//HEAD ' + "\n" +
        '(function(module) {' + "\n" +
        'try { app = angular.module("' + this.opt.name + '"); }' + "\n" +
        'catch(err) { app = angular.module("' + this.opt.name + '", []); }' + "\n" +
        'app.run(["$templateCache", function($templateCache) {' + "\n" +
        '"use strict";' + "\n";
};

NGAdapter.prototype.getFile = function (file, content) {
    return '$templateCache.put("' + file + '","' + this.escapeContent(content) + '")' + "\n";
};

NGAdapter.prototype.getFooter = function () {
    return '}]);' + "\n" + '})();';
};
NGAdapter.prototype.escapeContent = function (content) {
    var quoteChar = '"';
    var indentString = "  ";
    var bsRegexp = new RegExp('\\\\', 'g');
    var quoteRegexp = new RegExp('\\' + quoteChar, 'g');
    var nlReplace = '\\n' + quoteChar + ' +\n' + indentString + indentString + quoteChar;
    return content.replace(bsRegexp, '\\\\').replace(quoteRegexp, '\\' + quoteChar).replace(/\r?\n/g, nlReplace);
}
module.exports = NGAdapter;<commit_msg>Fix 'app is not defined' bug.<commit_after>'use strict';
function NGAdapter(opt) {
    this.opt = opt || {};
    this.opt.name = opt.name || '_html_';
    this.contentParts = [];
    this.separator = new Buffer(opt.separator);
};

NGAdapter.prototype.getHeader = function () {
    return '//HEAD ' + "\n" +
        '(function(app) {' + "\n" +
        'try { app = angular.module("' + this.opt.name + '"); }' + "\n" +
        'catch(err) { app = angular.module("' + this.opt.name + '", []); }' + "\n" +
        'app.run(["$templateCache", function($templateCache) {' + "\n" +
        '"use strict";' + "\n";
};

NGAdapter.prototype.getFile = function (file, content) {
    return '$templateCache.put("' + file + '","' + this.escapeContent(content) + '")' + "\n";
};

NGAdapter.prototype.getFooter = function () {
    return '}]);' + "\n" + '})();';
};
NGAdapter.prototype.escapeContent = function (content) {
    var quoteChar = '"';
    var indentString = "  ";
    var bsRegexp = new RegExp('\\\\', 'g');
    var quoteRegexp = new RegExp('\\' + quoteChar, 'g');
    var nlReplace = '\\n' + quoteChar + ' +\n' + indentString + indentString + quoteChar;
    return content.replace(bsRegexp, '\\\\').replace(quoteRegexp, '\\' + quoteChar).replace(/\r?\n/g, nlReplace);
}
module.exports = NGAdapter;
<|endoftext|>


<commit_before>goog.provide('ol.MapBrowserEvent');
goog.provide('ol.MapBrowserEvent.EventType');
goog.provide('ol.MapBrowserEventHandler');

goog.require('goog.array');
goog.require('goog.events');
goog.require('goog.events.BrowserEvent');
goog.require('goog.events.EventTarget');
goog.require('goog.events.EventType');
goog.require('goog.style');
goog.require('ol.BrowserFeature');
goog.require('ol.Coordinate');
goog.require('ol.FrameState');
goog.require('ol.MapEvent');
goog.require('ol.Pixel');

/**
 * @constructor
 * @extends {ol.MapEvent}
 * @param {string} type Event type.
 * @param {ol.Map} map Map.
 * @param {goog.events.BrowserEvent} browserEvent Browser event.
 * @param {?ol.FrameState=} opt_frameState Frame state.
 */
ol.MapBrowserEvent = function(type, map, browserEvent, opt_frameState) {

  goog.base(this, type, map, opt_frameState);

  /**
   * @type {goog.events.BrowserEvent}
   */
  this.browserEvent = browserEvent;

  /**
   * @private
   * @type {ol.Coordinate}
   */
  this.coordinate_ = null;

  /**
   * @type {boolean}
   */
  this.otherInteractionsStopped = false;

  /**
   * @private
   * @type {ol.Pixel}
   */
  this.pixel_ = null;

};
goog.inherits(ol.MapBrowserEvent, ol.MapEvent);

/**
 * IE specific events.
 * See http://msdn.microsoft.com/en-us/library/ie/hh673557(v=vs.85).aspx
 * FIXME: replace with goog.events.EventType enum once we use
 *        goog/events/eventtype.js above r2211
 * @enum {string}
 */
ol.MapBrowserEvent.IEEventType = {
  MSPOINTERDOWN: 'MSPointerDown',
  MSPOINTERMOVE: 'MSPointerMove',
  MSPOINTERUP: 'MSPointerUp'
};

/**
 * @return {ol.Coordinate} Coordinate.
 */
ol.MapBrowserEvent.prototype.getCoordinate = function() {
  if (goog.isNull(this.coordinate_)) {
    this.coordinate_ = this.map.getCoordinateFromPixel(this.getPixel());
  }
  return this.coordinate_;
};

/**
 * Get pixel offset of the event from the top-left corner of the map viewport.
 * @return {ol.Pixel} Pixel offset.
 */
ol.MapBrowserEvent.prototype.getPixel = function() {
  if (goog.isNull(this.pixel_)) {
    var eventPosition = goog.style.getRelativePosition(
        this.browserEvent, this.map.getViewport());
    this.pixel_ = [eventPosition.x, eventPosition.y];
  }
  return this.pixel_;
};

/**
 * @return {boolean} Do we have a left click?
 */
ol.MapBrowserEvent.prototype.isMouseActionButton = function() {
  // always assume a left-click on touch devices
  return ol.BrowserFeature.HAS_TOUCH ||
      this.browserEvent.isMouseActionButton();
};

/**
 * Prevents the default browser action.
 * @see https://developer.mozilla.org/en-US/docs/Web/API/event.preventDefault
 * @override
 */
ol.MapBrowserEvent.prototype.preventDefault = function() {
  goog.base(this, 'preventDefault');
  this.browserEvent.preventDefault();
};

/**
 * Stop the interaction chain.
 */
ol.MapBrowserEvent.prototype.stopOtherInteractions = function() {
  this.otherInteractionsStopped = true;
};

/**
 * Prevents further propagation of the current event.
 * @see https://developer.mozilla.org/en-US/docs/Web/API/event.stopPropagation
 * @override
 */
ol.MapBrowserEvent.prototype.stopPropagation = function() {
  goog.base(this, 'stopPropagation');
  this.browserEvent.stopPropagation();
};

/**
 * @param {ol.Map} map The map with the viewport to listen to events on.
 * @constructor
 * @extends {goog.events.EventTarget}
 */
ol.MapBrowserEventHandler = function(map) {

  goog.base(this);

  /**
   * This is the element that we will listen to the real events on.
   * @type {ol.Map}
   * @private
   */
  this.map_ = map;

  /**
   * @type {Object}
   * @private
   */
  this.previous_ = null;

  /**
   * @type {boolean}
   * @private
   */
  this.dragged_ = false;

  /**
   * Timestamp for the first click of a double click. Will be set back to 0
   * as soon as a double click is detected.
   * @type {?number}
   * @private
   */
  this.timestamp_ = null;

  /**
   * @type {Array.<number>}
   * @private
   */
  this.listenerKeys_ = null;

  /**
   * @type {Array.<number>}
   * @private
   */
  this.dragListenerKeys_ = null;

  /**
   * @type {Array.<number>}
   * @private
   */
  this.touchListenerKeys_ = null;

  /**
   * @type {goog.events.BrowserEvent}
   * @private
   */
  this.down_ = null;

  var element = this.map_.getViewport();
  this.listenerKeys_ = [
    goog.events.listen(element,
        [goog.events.EventType.CLICK, goog.events.EventType.DBLCLICK],
        this.click_, false, this),
    goog.events.listen(element,
        goog.events.EventType.MOUSEDOWN,
        this.handleMouseDown_, false, this),
    goog.events.listen(element,
        goog.events.EventType.MOUSEMOVE,
        this.relayEvent_, false, this),
    goog.events.listen(element,
        goog.events.EventType.MOUSEOUT,
        this.relayEvent_, false, this),
    goog.events.listen(element,
        goog.events.EventType.CONTEXTMENU,
        this.relayEvent_, false, this)
  ];
  // touch events
  this.touchListenerKeys_ = [
    goog.events.listen(element, [
      goog.events.EventType.TOUCHSTART,
      ol.MapBrowserEvent.IEEventType.MSPOINTERDOWN
    ], this.handleTouchStart_, false, this),
    goog.events.listen(element, [
      goog.events.EventType.TOUCHMOVE,
      ol.MapBrowserEvent.IEEventType.MSPOINTERMOVE
    ], this.handleTouchMove_, false, this),
    goog.events.listen(element, [
      goog.events.EventType.TOUCHEND,
      ol.MapBrowserEvent.IEEventType.MSPOINTERUP
    ], this.handleTouchEnd_, false, this)
  ];

};
goog.inherits(ol.MapBrowserEventHandler, goog.events.EventTarget);

/**
 * @param {goog.events.BrowserEvent} browserEvent Browser event.
 * @private
 */
ol.MapBrowserEventHandler.prototype.click_ = function(browserEvent) {
  if (!this.dragged_) {
    var newEvent;
    var type = browserEvent.type;
    if (this.timestamp_ === 0 || type == goog.events.EventType.DBLCLICK) {
      newEvent = new ol.MapBrowserEvent(
          ol.MapBrowserEvent.EventType.DBLCLICK, this.map_, browserEvent);
      this.dispatchEvent(newEvent);
    } else {
      newEvent = new ol.MapBrowserEvent(
          ol.MapBrowserEvent.EventType.CLICK, this.map_, browserEvent);
      this.dispatchEvent(newEvent);
    }
  }
};

/**
 * @param {goog.events.BrowserEvent} browserEvent Browser event.
 * @private
 */
ol.MapBrowserEventHandler.prototype.handleMouseUp_ = function(browserEvent) {
  if (this.previous_) {
    this.down_ = null;
    goog.array.forEach(this.dragListenerKeys_, goog.events.unlistenByKey);
    this.dragListenerKeys_ = null;
    this.previous_ = null;
    if (this.dragged_) {
      var newEvent = new ol.MapBrowserEvent(
          ol.MapBrowserEvent.EventType.DRAGEND, this.map_, browserEvent);
      this.dispatchEvent(newEvent);
    }
  }
};

/**
 * @param {goog.events.BrowserEvent} browserEvent Browser event.
 * @private
 */
ol.MapBrowserEventHandler.prototype.handleMouseDown_ = function(browserEvent) {
  var newEvent = new ol.MapBrowserEvent(
      ol.MapBrowserEvent.EventType.DOWN, this.map_, browserEvent);
  this.dispatchEvent(newEvent);
  if (!this.previous_) {
    this.down_ = browserEvent;
    this.previous_ = {
      clientX: browserEvent.clientX,
      clientY: browserEvent.clientY
    };
    this.dragged_ = false;
    this.dragListenerKeys_ = [
      goog.events.listen(goog.global.document, goog.events.EventType.MOUSEMOVE,
          this.handleMouseMove_, false, this),
      goog.events.listen(goog.global.document, goog.events.EventType.MOUSEUP,
          this.handleMouseUp_, false, this)
    ];
    // prevent browser image dragging with the dom renderer
    browserEvent.preventDefault();
  }
};

/**
 * @param {goog.events.BrowserEvent} browserEvent Browser event.
 * @private
 */
ol.MapBrowserEventHandler.prototype.handleMouseMove_ = function(browserEvent) {
  var newEvent;
  if (!this.dragged_) {
    this.dragged_ = true;
    newEvent = new ol.MapBrowserEvent(
        ol.MapBrowserEvent.EventType.DRAGSTART, this.map_, this.down_);
    this.dispatchEvent(newEvent);
  }
  this.previous_ = {
    clientX: browserEvent.clientX,
    clientY: browserEvent.clientY
  };
  newEvent = new ol.MapBrowserEvent(
      ol.MapBrowserEvent.EventType.DRAG, this.map_, browserEvent);
  this.dispatchEvent(newEvent);
};

/**
 * @param {goog.events.BrowserEvent} browserEvent Browser event.
 * @private
 */
ol.MapBrowserEventHandler.prototype.relayEvent_ = function(browserEvent) {
  this.dispatchEvent(new ol.MapBrowserEvent(
      browserEvent.type, this.map_, browserEvent));
};

/**
 * @param {goog.events.BrowserEvent} browserEvent Browser event.
 * @private
 */
ol.MapBrowserEventHandler.prototype.handleTouchStart_ = function(browserEvent) {
  // prevent context menu
  browserEvent.preventDefault();
  this.down_ = browserEvent;
  this.dragged_ = false;
  var newEvent = new ol.MapBrowserEvent(
      ol.MapBrowserEvent.EventType.TOUCHSTART, this.map_, browserEvent);
  this.dispatchEvent(newEvent);
};

/**
 * @param {goog.events.BrowserEvent} browserEvent Browser event.
 * @private
 */
ol.MapBrowserEventHandler.prototype.handleTouchMove_ = function(browserEvent) {
  this.dragged_ = true;
  var newEvent = new ol.MapBrowserEvent(
      ol.MapBrowserEvent.EventType.TOUCHMOVE, this.map_, browserEvent);
  this.dispatchEvent(newEvent);
};

/**
 * @param {goog.events.BrowserEvent} browserEvent Browser event.
 * @private
 */
ol.MapBrowserEventHandler.prototype.handleTouchEnd_ = function(browserEvent) {
  var newEvent = new ol.MapBrowserEvent(
      ol.MapBrowserEvent.EventType.TOUCHEND, this.map_, browserEvent);
  this.dispatchEvent(newEvent);
  if (!this.dragged_) {
    var now = goog.now();
    if (!this.timestamp_ || now - this.timestamp_ > 250) {
      this.timestamp_ = now;
    } else {
      this.timestamp_ = 0;
    }
    this.click_(this.down_);
  }
  this.down_ = null;
};

/**
 * FIXME empty description for jsdoc
 */
ol.MapBrowserEventHandler.prototype.disposeInternal = function() {
  if (!goog.isNull(this.listenerKeys_)) {
    goog.array.forEach(this.listenerKeys_, goog.events.unlistenByKey);
    this.listenerKeys_ = null;
  }
  if (!goog.isNull(this.dragListenerKeys_)) {
    goog.array.forEach(this.dragListenerKeys_, goog.events.unlistenByKey);
    this.dragListenerKeys_ = null;
  }
  if (!goog.isNull(this.touchListenerKeys_)) {
    goog.array.forEach(this.touchListenerKeys_, goog.events.unlistenByKey);
    this.touchListenerKeys_ = null;
  }
  goog.base(this, 'disposeInternal');
};

/**
 * Constants for event names.
 * @enum {string}
 */
ol.MapBrowserEvent.EventType = {
  CLICK: goog.events.EventType.CLICK,
  DBLCLICK: goog.events.EventType.DBLCLICK,
  DOWN: 'down',
  DRAGSTART: 'dragstart',
  DRAG: 'drag',
  DRAGEND: 'dragend',
  TOUCHSTART: goog.events.EventType.TOUCHSTART,
  TOUCHMOVE: goog.events.EventType.TOUCHMOVE,
  TOUCHEND: goog.events.EventType.TOUCHEND,
  MOUSEMOVE: goog.events.EventType.MOUSEMOVE,
  MOUSEOUT: goog.events.EventType.MOUSEOUT,
  CONTEXTMENU: goog.events.EventType.CONTEXTMENU
};
<commit_msg>Click handler called with empty event object on Android<commit_after>goog.provide('ol.MapBrowserEvent');
goog.provide('ol.MapBrowserEvent.EventType');
goog.provide('ol.MapBrowserEventHandler');

goog.require('goog.array');
goog.require('goog.events');
goog.require('goog.events.BrowserEvent');
goog.require('goog.events.EventTarget');
goog.require('goog.events.EventType');
goog.require('goog.style');
goog.require('ol.BrowserFeature');
goog.require('ol.Coordinate');
goog.require('ol.FrameState');
goog.require('ol.MapEvent');
goog.require('ol.Pixel');

/**
 * @constructor
 * @extends {ol.MapEvent}
 * @param {string} type Event type.
 * @param {ol.Map} map Map.
 * @param {goog.events.BrowserEvent} browserEvent Browser event.
 * @param {?ol.FrameState=} opt_frameState Frame state.
 */
ol.MapBrowserEvent = function(type, map, browserEvent, opt_frameState) {

  goog.base(this, type, map, opt_frameState);

  /**
   * @type {goog.events.BrowserEvent}
   */
  this.browserEvent = browserEvent;

  /**
   * @private
   * @type {ol.Coordinate}
   */
  this.coordinate_ = null;

  /**
   * @type {boolean}
   */
  this.otherInteractionsStopped = false;

  /**
   * @private
   * @type {ol.Pixel}
   */
  this.pixel_ = null;

};
goog.inherits(ol.MapBrowserEvent, ol.MapEvent);

/**
 * IE specific events.
 * See http://msdn.microsoft.com/en-us/library/ie/hh673557(v=vs.85).aspx
 * FIXME: replace with goog.events.EventType enum once we use
 *        goog/events/eventtype.js above r2211
 * @enum {string}
 */
ol.MapBrowserEvent.IEEventType = {
  MSPOINTERDOWN: 'MSPointerDown',
  MSPOINTERMOVE: 'MSPointerMove',
  MSPOINTERUP: 'MSPointerUp'
};

/**
 * @return {ol.Coordinate} Coordinate.
 */
ol.MapBrowserEvent.prototype.getCoordinate = function() {
  if (goog.isNull(this.coordinate_)) {
    this.coordinate_ = this.map.getCoordinateFromPixel(this.getPixel());
  }
  return this.coordinate_;
};

/**
 * Get pixel offset of the event from the top-left corner of the map viewport.
 * @return {ol.Pixel} Pixel offset.
 */
ol.MapBrowserEvent.prototype.getPixel = function() {
  if (goog.isNull(this.pixel_)) {
    var eventPosition = goog.style.getRelativePosition(
        this.browserEvent, this.map.getViewport());
    this.pixel_ = [eventPosition.x, eventPosition.y];
  }
  return this.pixel_;
};

/**
 * @return {boolean} Do we have a left click?
 */
ol.MapBrowserEvent.prototype.isMouseActionButton = function() {
  // always assume a left-click on touch devices
  return ol.BrowserFeature.HAS_TOUCH ||
      this.browserEvent.isMouseActionButton();
};

/**
 * Prevents the default browser action.
 * @see https://developer.mozilla.org/en-US/docs/Web/API/event.preventDefault
 * @override
 */
ol.MapBrowserEvent.prototype.preventDefault = function() {
  goog.base(this, 'preventDefault');
  this.browserEvent.preventDefault();
};

/**
 * Stop the interaction chain.
 */
ol.MapBrowserEvent.prototype.stopOtherInteractions = function() {
  this.otherInteractionsStopped = true;
};

/**
 * Prevents further propagation of the current event.
 * @see https://developer.mozilla.org/en-US/docs/Web/API/event.stopPropagation
 * @override
 */
ol.MapBrowserEvent.prototype.stopPropagation = function() {
  goog.base(this, 'stopPropagation');
  this.browserEvent.stopPropagation();
};

/**
 * @param {ol.Map} map The map with the viewport to listen to events on.
 * @constructor
 * @extends {goog.events.EventTarget}
 */
ol.MapBrowserEventHandler = function(map) {

  goog.base(this);

  /**
   * This is the element that we will listen to the real events on.
   * @type {ol.Map}
   * @private
   */
  this.map_ = map;

  /**
   * @type {Object}
   * @private
   */
  this.previous_ = null;

  /**
   * @type {boolean}
   * @private
   */
  this.dragged_ = false;

  /**
   * Timestamp for the first click of a double click. Will be set back to 0
   * as soon as a double click is detected.
   * @type {?number}
   * @private
   */
  this.timestamp_ = null;

  /**
   * @type {Array.<number>}
   * @private
   */
  this.listenerKeys_ = null;

  /**
   * @type {Array.<number>}
   * @private
   */
  this.dragListenerKeys_ = null;

  /**
   * @type {Array.<number>}
   * @private
   */
  this.touchListenerKeys_ = null;

  /**
   * @type {goog.events.BrowserEvent}
   * @private
   */
  this.down_ = null;

  var element = this.map_.getViewport();
  this.listenerKeys_ = [
    goog.events.listen(element,
        [goog.events.EventType.CLICK, goog.events.EventType.DBLCLICK],
        this.click_, false, this),
    goog.events.listen(element,
        goog.events.EventType.MOUSEDOWN,
        this.handleMouseDown_, false, this),
    goog.events.listen(element,
        goog.events.EventType.MOUSEMOVE,
        this.relayEvent_, false, this),
    goog.events.listen(element,
        goog.events.EventType.MOUSEOUT,
        this.relayEvent_, false, this),
    goog.events.listen(element,
        goog.events.EventType.CONTEXTMENU,
        this.relayEvent_, false, this)
  ];
  // touch events
  this.touchListenerKeys_ = [
    goog.events.listen(element, [
      goog.events.EventType.TOUCHSTART,
      ol.MapBrowserEvent.IEEventType.MSPOINTERDOWN
    ], this.handleTouchStart_, false, this),
    goog.events.listen(element, [
      goog.events.EventType.TOUCHMOVE,
      ol.MapBrowserEvent.IEEventType.MSPOINTERMOVE
    ], this.handleTouchMove_, false, this),
    goog.events.listen(element, [
      goog.events.EventType.TOUCHEND,
      ol.MapBrowserEvent.IEEventType.MSPOINTERUP
    ], this.handleTouchEnd_, false, this)
  ];

};
goog.inherits(ol.MapBrowserEventHandler, goog.events.EventTarget);

/**
 * @param {goog.events.BrowserEvent} browserEvent Browser event.
 * @private
 */
ol.MapBrowserEventHandler.prototype.click_ = function(browserEvent) {
  if (!this.dragged_) {
    var newEvent;
    var type = browserEvent.type;
    if (this.timestamp_ === 0 || type == goog.events.EventType.DBLCLICK) {
      newEvent = new ol.MapBrowserEvent(
          ol.MapBrowserEvent.EventType.DBLCLICK, this.map_, browserEvent);
      this.dispatchEvent(newEvent);
    } else {
      newEvent = new ol.MapBrowserEvent(
          ol.MapBrowserEvent.EventType.CLICK, this.map_, browserEvent);
      this.dispatchEvent(newEvent);
    }
  }
};

/**
 * @param {goog.events.BrowserEvent} browserEvent Browser event.
 * @private
 */
ol.MapBrowserEventHandler.prototype.handleMouseUp_ = function(browserEvent) {
  if (this.previous_) {
    this.down_ = null;
    goog.array.forEach(this.dragListenerKeys_, goog.events.unlistenByKey);
    this.dragListenerKeys_ = null;
    this.previous_ = null;
    if (this.dragged_) {
      var newEvent = new ol.MapBrowserEvent(
          ol.MapBrowserEvent.EventType.DRAGEND, this.map_, browserEvent);
      this.dispatchEvent(newEvent);
    }
  }
};

/**
 * @param {goog.events.BrowserEvent} browserEvent Browser event.
 * @private
 */
ol.MapBrowserEventHandler.prototype.handleMouseDown_ = function(browserEvent) {
  var newEvent = new ol.MapBrowserEvent(
      ol.MapBrowserEvent.EventType.DOWN, this.map_, browserEvent);
  this.dispatchEvent(newEvent);
  if (!this.previous_) {
    this.down_ = browserEvent;
    this.previous_ = {
      clientX: browserEvent.clientX,
      clientY: browserEvent.clientY
    };
    this.dragged_ = false;
    this.dragListenerKeys_ = [
      goog.events.listen(goog.global.document, goog.events.EventType.MOUSEMOVE,
          this.handleMouseMove_, false, this),
      goog.events.listen(goog.global.document, goog.events.EventType.MOUSEUP,
          this.handleMouseUp_, false, this)
    ];
    // prevent browser image dragging with the dom renderer
    browserEvent.preventDefault();
  }
};

/**
 * @param {goog.events.BrowserEvent} browserEvent Browser event.
 * @private
 */
ol.MapBrowserEventHandler.prototype.handleMouseMove_ = function(browserEvent) {
  var newEvent;
  if (!this.dragged_) {
    this.dragged_ = true;
    newEvent = new ol.MapBrowserEvent(
        ol.MapBrowserEvent.EventType.DRAGSTART, this.map_, this.down_);
    this.dispatchEvent(newEvent);
  }
  this.previous_ = {
    clientX: browserEvent.clientX,
    clientY: browserEvent.clientY
  };
  newEvent = new ol.MapBrowserEvent(
      ol.MapBrowserEvent.EventType.DRAG, this.map_, browserEvent);
  this.dispatchEvent(newEvent);
};

/**
 * @param {goog.events.BrowserEvent} browserEvent Browser event.
 * @private
 */
ol.MapBrowserEventHandler.prototype.relayEvent_ = function(browserEvent) {
  this.dispatchEvent(new ol.MapBrowserEvent(
      browserEvent.type, this.map_, browserEvent));
};

/**
 * @param {goog.events.BrowserEvent} browserEvent Browser event.
 * @private
 */
ol.MapBrowserEventHandler.prototype.handleTouchStart_ = function(browserEvent) {
  // prevent context menu
  browserEvent.preventDefault();
  this.down_ = browserEvent;
  this.dragged_ = false;
  var newEvent = new ol.MapBrowserEvent(
      ol.MapBrowserEvent.EventType.TOUCHSTART, this.map_, browserEvent);
  this.dispatchEvent(newEvent);
};

/**
 * @param {goog.events.BrowserEvent} browserEvent Browser event.
 * @private
 */
ol.MapBrowserEventHandler.prototype.handleTouchMove_ = function(browserEvent) {
  this.dragged_ = true;
  var newEvent = new ol.MapBrowserEvent(
      ol.MapBrowserEvent.EventType.TOUCHMOVE, this.map_, browserEvent);
  this.dispatchEvent(newEvent);
};

/**
 * @param {goog.events.BrowserEvent} browserEvent Browser event.
 * @private
 */
ol.MapBrowserEventHandler.prototype.handleTouchEnd_ = function(browserEvent) {
  var newEvent = new ol.MapBrowserEvent(
      ol.MapBrowserEvent.EventType.TOUCHEND, this.map_, browserEvent);
  this.dispatchEvent(newEvent);
  if (!this.dragged_) {
    var now = goog.now();
    if (!this.timestamp_ || now - this.timestamp_ > 250) {
      this.timestamp_ = now;
    } else {
      this.timestamp_ = 0;
    }
    if (!goog.isNull(this.down_)) {
      this.click_(this.down_);
    }
  }
  this.down_ = null;
};

/**
 * FIXME empty description for jsdoc
 */
ol.MapBrowserEventHandler.prototype.disposeInternal = function() {
  if (!goog.isNull(this.listenerKeys_)) {
    goog.array.forEach(this.listenerKeys_, goog.events.unlistenByKey);
    this.listenerKeys_ = null;
  }
  if (!goog.isNull(this.dragListenerKeys_)) {
    goog.array.forEach(this.dragListenerKeys_, goog.events.unlistenByKey);
    this.dragListenerKeys_ = null;
  }
  if (!goog.isNull(this.touchListenerKeys_)) {
    goog.array.forEach(this.touchListenerKeys_, goog.events.unlistenByKey);
    this.touchListenerKeys_ = null;
  }
  goog.base(this, 'disposeInternal');
};

/**
 * Constants for event names.
 * @enum {string}
 */
ol.MapBrowserEvent.EventType = {
  CLICK: goog.events.EventType.CLICK,
  DBLCLICK: goog.events.EventType.DBLCLICK,
  DOWN: 'down',
  DRAGSTART: 'dragstart',
  DRAG: 'drag',
  DRAGEND: 'dragend',
  TOUCHSTART: goog.events.EventType.TOUCHSTART,
  TOUCHMOVE: goog.events.EventType.TOUCHMOVE,
  TOUCHEND: goog.events.EventType.TOUCHEND,
  MOUSEMOVE: goog.events.EventType.MOUSEMOVE,
  MOUSEOUT: goog.events.EventType.MOUSEOUT,
  CONTEXTMENU: goog.events.EventType.CONTEXTMENU
};
<|endoftext|>