<commit_before>import { Map, OrderedMap, Record } from 'immutable'
import cuid from 'cuid'
import errors from 'http-errors'
import { Mount, Api, registerApiRoutes } from '../websockets/api-decorators'

function validateBody(bodyValidators) {
  return async function(data, next) {
    const body = data.get('body')
    if (!body) throw new errors.BadRequest('invalid body')
    for (const key of Object.keys(bodyValidators)) {
      if (!bodyValidators[key](body[key])) {
        throw new errors.BadRequest(`Invalid ${key}`)
      }
    }

    return await next(data)
  }
}

const nonEmptyString = str => typeof str === 'string' && str.length > 0

const Player = new Record({ name: null, id: null, race: 'r', isComputer: false, slot: -1 })

export const Players = {
  createHuman(name, race, slot) {
    return new Player({ name, race, id: cuid(), isComputer: false, slot })
  },

  createComputer(race, slot) {
    return new Player({ name: 'robit', race, id: cuid(), isComputer: true, slot })
  },
}

const Lobby = new Record({
  name: null,
  map: null,
  numSlots: 0,
  players: new OrderedMap(),
  hostId: null,
})

export const Lobbies = {
  // Creates a new lobby, and an initial host player in the first slot.
  create(name, map, numSlots, hostName, hostRace = 'r') {
    const host = Players.createHuman(hostName, hostRace, 0)
    return new Lobby({
      name,
      map,
      numSlots,
      players: new OrderedMap({ [host.id]: host }),
      hostId: host.id
    })
  },

  // Serializes a lobby to a summary-form in JSON, suitable for e.g. displaying a list of all the
  // open lobbies.
  toSummaryJson(lobby) {
    return JSON.stringify({
      name: lobby.name,
      map: lobby.map,
      numSlots: lobby.numSlots,
      host: { name: lobby.getIn(['players', lobby.hostId, 'name']), id: lobby.hostId },
      filledSlots: lobby.players.size,
    })
  },

  // Finds the next empty slot in the lobby. Returns -1 if there are no available slots.
  findEmptySlot(lobby) {
    if (lobby.numSlots <= lobby.players.size) {
      return -1
    }

    const slots = lobby.players.map(p => p.slot).toSet()
    for (let s = 0; s < lobby.numSlots; s++) {
      if (!slots.has(s)) {
        return s
      }
    }
  },

  // Adds a player to the lobby, returning the updated lobby. The player should already have the
  // proper slot set (see #findEmptySlot).
  addPlayer(lobby, player) {
    if (player.slot < 0 || player.slot >= lobby.numSlots) {
      throw new Error('slot out of bounds')
    } else if (lobby.players.some(p => p.slot === player.slot)) {
      throw new Error('slot conflict')
    }

    return lobby.setIn(['players', player.id], player)
  },

  // Updates the race of a particular player, returning the updated lobby.
  setRace(lobby, id, newRace) {
    return lobby.setIn(['players', id, 'race'], newRace)
  },

  // Removes the player with specified `id` from a lobby, returning the updated lobby. If the lobby
  // is closed (e.g. because it no longer has any human players), null will be returned. Note that
  // if the host is being removed, a new, suitable host will be chosen.
  removePlayerById(lobby, id) {
    const updated = lobby.deleteIn(['players', id])
    if (updated === lobby) {
      // nothing removed, e.g. player wasn't in the lobby
      return lobby
    }

    if (updated.players.isEmpty()) {
      return null
    }

    if (lobby.hostId === id) {
      // the player we removed was the host, find a new host
      const newHost = updated.players.skipWhile(p => p.isComputer).first()
      // if a new host was found, set their ID, else close the lobby (only computers left)
      return newHost ? updated.set('hostId', newHost.id) : null
    }

    return updated
  },

  // Finds the player with the specified name in the lobby. Only works for human players (computer
  // players do not have unique names). If no player is found, undefined will be returned.
  findPlayerByName(lobby, name) {
    return lobby.players.find(p => !p.isComputer && p.name === name)
  },

  // Finds the player with the specified slot number in the lobby. If no player is found, undefined
  // will be returned.
  findPlayerBySlot(lobby, slotNum) {
    return lobby.players.find(p => p.slot === slotNum)
  }
}

const playerIdNum = id => id.length >= 21 && id.length <= 29
const slotNum = s => s >= 0 && s <= 7
const slotNumInRange = s => s >= 2 && s <= 8

const MOUNT_BASE = '/lobbies'

@Mount(MOUNT_BASE)
export class LobbyApi {
  constructor(nydus, userSockets) {
    this.nydus = nydus
    this.userSockets = userSockets
    this.lobbies = new Map()
    this.lobbyUsers = new Map()
  }

  @Api('/create',
      validateBody({
        name: nonEmptyString,
        map: nonEmptyString,
        numSlots: slotNumInRange,
      }),
      'getUser',
      'ensureNotInLobby')
  async create(data, next) {
    const { name, map, numSlots } = data.get('body')
    const user = data.get('user')

    if (this.lobbies.has(name)) {
      throw new errors.Conflict('already another lobby with that name')
    }

    const lobby = Lobbies.create(name, map, numSlots, user.name)
    this.lobbies = this.lobbies.set(name, lobby)
    this.lobbyUsers = this.lobbyUsers.set(user, name)
    this._subscribeUserToLobby(lobby, user)
  }

  @Api('/join',
    validateBody({
      name: nonEmptyString,
    }),
    'getUser',
    'ensureNotInLobby')
  async join(data, next) {
    const { name } = data.get('body')
    const user = data.get('user')

    if (!this.lobbies.has(name)) {
      throw new errors.NotFound('no lobby found with that name')
    }

    let lobby = this.lobbies.get(name)
    const slot = Lobbies.findEmptySlot(lobby)
    if (slot < 0) {
      throw new errors.Conflict('lobby is full')
    }
    const player = Players.createHuman(user.name, 'r', slot)
    lobby = Lobbies.addPlayer(lobby, player)
    this.lobbies = this.lobbies.set(name, lobby)
    this.lobbyUsers = this.lobbyUsers.set(user, name)

    this._publishTo(lobby, {
      type: 'join',
      player,
    })
    this._subscribeUserToLobby(lobby, user)
  }

  _subscribeUserToLobby(lobby, user) {
    const lobbyName = lobby.name
    user.subscribe(LobbyApi._getPath(lobby), () => {
      const lobby = this.lobbies.get(lobbyName)
      const myId = Lobbies.findPlayerByName(lobby, user.name).id
      return {
        type: 'init',
        lobby,
        myId,
      }
    }, user => this._removeUserFromLobby(this.lobbies.get(lobbyName), user))
  }

  @Api('/addComputer',
    validateBody({
      slotNum
    }),
    'getUser',
    'getLobby',
    'getPlayer',
    'ensureIsLobbyHost')
  async addComputer(data, next) {
    const { slotNum } = data.get('body')
    let lobby = data.get('lobby')

    if (Lobbies.findPlayerBySlot(lobby, slotNum)) {
      throw new errors.BadRequest('invalid slot')
    }

    const computer = Players.createComputer('r', slotNum)
    lobby = Lobbies.addPlayer(lobby, computer)
    this.lobbies = this.lobbies.set(lobby.name, lobby)

    this._publishTo(lobby, {
      type: 'join',
      player: computer,
    })
  }

  @Api('/setRace',
    validateBody({
      id: playerIdNum,
      race: nonEmptyString,
    }),
    'getUser',
    'getLobby',
    'getPlayer')
  async setRace(data, next) {
    const { id, race } = data.get('body')
    const lobby = data.get('lobby')
    const player = data.get('player')

    if (race !== 'z' && race !== 't' && race !== 'p' && race !== 'r') {
      throw new errors.BadRequest('invalid race')
    }

    if (!lobby.players.has(id)) {
      throw new errors.BadRequest('invalid id')
    }

    const playerToSetRace = lobby.players.get(id)
    if (!playerToSetRace.isComputer && player.id !== playerToSetRace.id) {
      throw new errors.Forbidden('cannot set other user\'s races')
    } else if (playerToSetRace.isComputer) {
      await this.ensureIsLobbyHost(data, () => Promise.resolve())
    }

    const updatedLobby = Lobbies.setRace(lobby, id, race)
    this.lobbies = this.lobbies.set(lobby.name, updatedLobby)

    this._publishTo(lobby, {
      type: 'raceChange',
      id,
      newRace: race,
    })
  }

  @Api('/leave',
    'getUser',
    'getLobby')
  async leave(data, next) {
    const lobby = data.get('lobby')
    const user = data.get('user')
    this._removeUserFromLobby(lobby, user)
  }

  _removeUserFromLobby(lobby, user) {
    const id = Lobbies.findPlayerByName(lobby, user.name).id
    const updatedLobby = Lobbies.removePlayerById(lobby, id)

    if (!updatedLobby) {
      this.lobbies = this.lobbies.delete(lobby.name)
    } else {
      this.lobbies = this.lobbies.set(lobby.name, updatedLobby)
    }
    this.lobbyUsers = this.lobbyUsers.delete(user)

    if (updatedLobby && updatedLobby.hostId !== lobby.hostId) {
      this._publishTo(lobby, {
        type: 'hostChange',
        newId: updatedLobby.hostId,
      })
    }

    this._publishTo(lobby, {
      type: 'leave',
      id,
    })
    user.unsubscribe(LobbyApi._getPath(lobby))
  }

  async getUser(data, next) {
    const user = this.userSockets.getBySocket(data.get('client'))
    if (!user) throw new errors.Unauthorized('authorization required')
    const newData = data.set('user', user)

    return await next(newData)
  }

  async getLobby(data, next) {
    const user = data.get('user')
    if (!this.lobbyUsers.has(user)) {
      throw new errors.BadRequest('must be in a lobby')
    }
    const newData = data.set('lobby', this.lobbies.get(this.lobbyUsers.get(user)))

    return await next(newData)
  }

  async getPlayer(data, next) {
    const user = data.get('user')
    const lobby = data.get('lobby')

    const newData = data.set('player', Lobbies.findPlayerByName(lobby, user.name))

    return await next(newData)
  }

  async ensureNotInLobby(data, next) {
    if (this.lobbyUsers.has(data.get('user'))) {
      throw new errors.Conflict('cannot enter multiple lobbies at once')
    }

    return await next(data)
  }

  async ensureIsLobbyHost(data, next) {
    const lobby = data.get('lobby')
    const id = data.get('player').id

    if (id !== lobby.hostId) {
      throw new errors.Unauthorized('must be a lobby host')
    }

    return await next(data)
  }

  _publishTo(lobby, data) {
    this.nydus.publish(LobbyApi._getPath(lobby), data)
  }

  static _getPath(lobby) {
    return `${MOUNT_BASE}/${encodeURIComponent(lobby.name)}`
  }
}

export default function registerApi(nydus, userSockets) {
  const api = new LobbyApi(nydus, userSockets)
  registerApiRoutes(api, nydus)
  return api
}
<commit_msg>Add validation function for race instead of doing it ad-hoc, remove validation function for id's.<commit_after>import { Map, OrderedMap, Record } from 'immutable'
import cuid from 'cuid'
import errors from 'http-errors'
import { Mount, Api, registerApiRoutes } from '../websockets/api-decorators'

function validateBody(bodyValidators) {
  return async function(data, next) {
    const body = data.get('body')
    if (!body) throw new errors.BadRequest('invalid body')
    for (const key of Object.keys(bodyValidators)) {
      if (!bodyValidators[key](body[key])) {
        throw new errors.BadRequest(`Invalid ${key}`)
      }
    }

    return await next(data)
  }
}

const nonEmptyString = str => typeof str === 'string' && str.length > 0

const Player = new Record({ name: null, id: null, race: 'r', isComputer: false, slot: -1 })

export const Players = {
  createHuman(name, race, slot) {
    return new Player({ name, race, id: cuid(), isComputer: false, slot })
  },

  createComputer(race, slot) {
    return new Player({ name: 'robit', race, id: cuid(), isComputer: true, slot })
  },
}

const Lobby = new Record({
  name: null,
  map: null,
  numSlots: 0,
  players: new OrderedMap(),
  hostId: null,
})

export const Lobbies = {
  // Creates a new lobby, and an initial host player in the first slot.
  create(name, map, numSlots, hostName, hostRace = 'r') {
    const host = Players.createHuman(hostName, hostRace, 0)
    return new Lobby({
      name,
      map,
      numSlots,
      players: new OrderedMap({ [host.id]: host }),
      hostId: host.id
    })
  },

  // Serializes a lobby to a summary-form in JSON, suitable for e.g. displaying a list of all the
  // open lobbies.
  toSummaryJson(lobby) {
    return JSON.stringify({
      name: lobby.name,
      map: lobby.map,
      numSlots: lobby.numSlots,
      host: { name: lobby.getIn(['players', lobby.hostId, 'name']), id: lobby.hostId },
      filledSlots: lobby.players.size,
    })
  },

  // Finds the next empty slot in the lobby. Returns -1 if there are no available slots.
  findEmptySlot(lobby) {
    if (lobby.numSlots <= lobby.players.size) {
      return -1
    }

    const slots = lobby.players.map(p => p.slot).toSet()
    for (let s = 0; s < lobby.numSlots; s++) {
      if (!slots.has(s)) {
        return s
      }
    }
  },

  // Adds a player to the lobby, returning the updated lobby. The player should already have the
  // proper slot set (see #findEmptySlot).
  addPlayer(lobby, player) {
    if (player.slot < 0 || player.slot >= lobby.numSlots) {
      throw new Error('slot out of bounds')
    } else if (lobby.players.some(p => p.slot === player.slot)) {
      throw new Error('slot conflict')
    }

    return lobby.setIn(['players', player.id], player)
  },

  // Updates the race of a particular player, returning the updated lobby.
  setRace(lobby, id, newRace) {
    return lobby.setIn(['players', id, 'race'], newRace)
  },

  // Removes the player with specified `id` from a lobby, returning the updated lobby. If the lobby
  // is closed (e.g. because it no longer has any human players), null will be returned. Note that
  // if the host is being removed, a new, suitable host will be chosen.
  removePlayerById(lobby, id) {
    const updated = lobby.deleteIn(['players', id])
    if (updated === lobby) {
      // nothing removed, e.g. player wasn't in the lobby
      return lobby
    }

    if (updated.players.isEmpty()) {
      return null
    }

    if (lobby.hostId === id) {
      // the player we removed was the host, find a new host
      const newHost = updated.players.skipWhile(p => p.isComputer).first()
      // if a new host was found, set their ID, else close the lobby (only computers left)
      return newHost ? updated.set('hostId', newHost.id) : null
    }

    return updated
  },

  // Finds the player with the specified name in the lobby. Only works for human players (computer
  // players do not have unique names). If no player is found, undefined will be returned.
  findPlayerByName(lobby, name) {
    return lobby.players.find(p => !p.isComputer && p.name === name)
  },

  // Finds the player with the specified slot number in the lobby. If no player is found, undefined
  // will be returned.
  findPlayerBySlot(lobby, slotNum) {
    return lobby.players.find(p => p.slot === slotNum)
  }
}

const slotNum = s => s >= 0 && s <= 7
const slotNumInRange = s => s >= 2 && s <= 8
const validRace = r => r === 'r' || r === 't' || r === 'z' || r === 'p'

const MOUNT_BASE = '/lobbies'

@Mount(MOUNT_BASE)
export class LobbyApi {
  constructor(nydus, userSockets) {
    this.nydus = nydus
    this.userSockets = userSockets
    this.lobbies = new Map()
    this.lobbyUsers = new Map()
  }

  @Api('/create',
      validateBody({
        name: nonEmptyString,
        map: nonEmptyString,
        numSlots: slotNumInRange,
      }),
      'getUser',
      'ensureNotInLobby')
  async create(data, next) {
    const { name, map, numSlots } = data.get('body')
    const user = data.get('user')

    if (this.lobbies.has(name)) {
      throw new errors.Conflict('already another lobby with that name')
    }

    const lobby = Lobbies.create(name, map, numSlots, user.name)
    this.lobbies = this.lobbies.set(name, lobby)
    this.lobbyUsers = this.lobbyUsers.set(user, name)
    this._subscribeUserToLobby(lobby, user)
  }

  @Api('/join',
    validateBody({
      name: nonEmptyString,
    }),
    'getUser',
    'ensureNotInLobby')
  async join(data, next) {
    const { name } = data.get('body')
    const user = data.get('user')

    if (!this.lobbies.has(name)) {
      throw new errors.NotFound('no lobby found with that name')
    }

    let lobby = this.lobbies.get(name)
    const slot = Lobbies.findEmptySlot(lobby)
    if (slot < 0) {
      throw new errors.Conflict('lobby is full')
    }
    const player = Players.createHuman(user.name, 'r', slot)
    lobby = Lobbies.addPlayer(lobby, player)
    this.lobbies = this.lobbies.set(name, lobby)
    this.lobbyUsers = this.lobbyUsers.set(user, name)

    this._publishTo(lobby, {
      type: 'join',
      player,
    })
    this._subscribeUserToLobby(lobby, user)
  }

  _subscribeUserToLobby(lobby, user) {
    const lobbyName = lobby.name
    user.subscribe(LobbyApi._getPath(lobby), () => {
      const lobby = this.lobbies.get(lobbyName)
      const myId = Lobbies.findPlayerByName(lobby, user.name).id
      return {
        type: 'init',
        lobby,
        myId,
      }
    }, user => this._removeUserFromLobby(this.lobbies.get(lobbyName), user))
  }

  @Api('/addComputer',
    validateBody({
      slotNum
    }),
    'getUser',
    'getLobby',
    'getPlayer',
    'ensureIsLobbyHost')
  async addComputer(data, next) {
    const { slotNum } = data.get('body')
    let lobby = data.get('lobby')

    if (Lobbies.findPlayerBySlot(lobby, slotNum)) {
      throw new errors.BadRequest('invalid slot')
    }

    const computer = Players.createComputer('r', slotNum)
    lobby = Lobbies.addPlayer(lobby, computer)
    this.lobbies = this.lobbies.set(lobby.name, lobby)

    this._publishTo(lobby, {
      type: 'join',
      player: computer,
    })
  }

  @Api('/setRace',
    validateBody({
      id: nonEmptyString,
      race: validRace,
    }),
    'getUser',
    'getLobby',
    'getPlayer')
  async setRace(data, next) {
    const { id, race } = data.get('body')
    const lobby = data.get('lobby')
    const player = data.get('player')

    if (!lobby.players.has(id)) {
      throw new errors.BadRequest('invalid id')
    }

    const playerToSetRace = lobby.players.get(id)
    if (!playerToSetRace.isComputer && player.id !== playerToSetRace.id) {
      throw new errors.Forbidden('cannot set other user\'s races')
    } else if (playerToSetRace.isComputer) {
      await this.ensureIsLobbyHost(data, () => Promise.resolve())
    }

    const updatedLobby = Lobbies.setRace(lobby, id, race)
    this.lobbies = this.lobbies.set(lobby.name, updatedLobby)

    this._publishTo(lobby, {
      type: 'raceChange',
      id,
      newRace: race,
    })
  }

  @Api('/leave',
    'getUser',
    'getLobby')
  async leave(data, next) {
    const lobby = data.get('lobby')
    const user = data.get('user')
    this._removeUserFromLobby(lobby, user)
  }

  _removeUserFromLobby(lobby, user) {
    const id = Lobbies.findPlayerByName(lobby, user.name).id
    const updatedLobby = Lobbies.removePlayerById(lobby, id)

    if (!updatedLobby) {
      this.lobbies = this.lobbies.delete(lobby.name)
    } else {
      this.lobbies = this.lobbies.set(lobby.name, updatedLobby)
    }
    this.lobbyUsers = this.lobbyUsers.delete(user)

    if (updatedLobby && updatedLobby.hostId !== lobby.hostId) {
      this._publishTo(lobby, {
        type: 'hostChange',
        newId: updatedLobby.hostId,
      })
    }

    this._publishTo(lobby, {
      type: 'leave',
      id,
    })
    user.unsubscribe(LobbyApi._getPath(lobby))
  }

  async getUser(data, next) {
    const user = this.userSockets.getBySocket(data.get('client'))
    if (!user) throw new errors.Unauthorized('authorization required')
    const newData = data.set('user', user)

    return await next(newData)
  }

  async getLobby(data, next) {
    const user = data.get('user')
    if (!this.lobbyUsers.has(user)) {
      throw new errors.BadRequest('must be in a lobby')
    }
    const newData = data.set('lobby', this.lobbies.get(this.lobbyUsers.get(user)))

    return await next(newData)
  }

  async getPlayer(data, next) {
    const user = data.get('user')
    const lobby = data.get('lobby')

    const newData = data.set('player', Lobbies.findPlayerByName(lobby, user.name))

    return await next(newData)
  }

  async ensureNotInLobby(data, next) {
    if (this.lobbyUsers.has(data.get('user'))) {
      throw new errors.Conflict('cannot enter multiple lobbies at once')
    }

    return await next(data)
  }

  async ensureIsLobbyHost(data, next) {
    const lobby = data.get('lobby')
    const id = data.get('player').id

    if (id !== lobby.hostId) {
      throw new errors.Unauthorized('must be a lobby host')
    }

    return await next(data)
  }

  _publishTo(lobby, data) {
    this.nydus.publish(LobbyApi._getPath(lobby), data)
  }

  static _getPath(lobby) {
    return `${MOUNT_BASE}/${encodeURIComponent(lobby.name)}`
  }
}

export default function registerApi(nydus, userSockets) {
  const api = new LobbyApi(nydus, userSockets)
  registerApiRoutes(api, nydus)
  return api
}
<|endoftext|>


<commit_before>// ==UserScript==
// @name       *mail.yandex.ru blocks all images from amazon, ebay, optional load images by click
// @namespace  http://gubnota.github.io/fenki_js_helpers/plugin/monkey/mail_yandex_ru_adds/
// @version    0.0.5
// @downloadURL http://gubnota.github.io/fenki_js_helpers/plugin/monkey/mail_yandex_ru_adds/hide_img.user.js
// @description removes adds block(s) in mail.yeah.net
// @include      http://*mail.yandex.*/*
// @include      https://*mail.yandex.*/*
// @copyright  2016+, Vladislav Muravyev
// @author Vladislav Muravyev
// @grant          none
// @icon http://gubnota.github.io/fenki_js_helpers/plugin/monkey/mail_yandex_ru_adds/yandex.ico
// @run-at document-start
// ==/UserScript==
(function(){

var imgscope='.mail-Message-Body *',/*image searching scope*/
empty_dot="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==",/*.placedb-letter*/
click_handlers='.ns-view-messages-item',/*on click which items to (re)-run hide images*/
insert_button_place='.ns-view-message-toolbar',/*where to insert show images button*/
button_id='show_img',/*button id to show images*/
button_code='Показать картинки',
button_where='afterBegin',
button_from='Показ',
button_to='Спрят',
button_search='з',
main_interval_reload=2000;
function bgimg_handler(el){
if(el.style.backgroundImage){
	if (!el.getAttribute('old-bgimg')){
	el.setAttribute('old-bgimg',el.style.backgroundImage.replace(/(.*)/,'/*$1*/'));
	el.style.backgroundImage="url("+empty_dot+")";
	}
	else{
	el.style.backgroundImage=el.getAttribute('old-bgimg').replace(/\/\*(.*)\*\//,'$1');
	el.removeAttribute('old-bgimg');
	}
}
}
function attr_handler(el,attr){
	attr.forEach(function(at){
	if (!el.getAttribute('old-'+at) && el.getAttribute(at)){
	el.setAttribute('old-'+at,el.getAttribute(at));
	el.setAttribute(at,empty_dot);
	}
	else if (el.getAttribute('old-'+at)){
	el.setAttribute(at,el.getAttribute('old-'+at));
	el.removeAttribute('old-'+at);
	}
	});
}

function hide_show_letter_img(){
[].forEach.call(document.querySelectorAll(imgscope),function(el) {
bgimg_handler(el);/*bg-img*/

if (el.nodeName=='IMG') {
	bgimg_handler(el);
	attr_handler(el,['src','srcset']);
}/*img src*/
});}

function init_find_place(){
var a = document.querySelectorAll(insert_button_place);
var b=document.getElementById(button_id);

if (b === null && a.length>0){
a[0].insertAdjacentHTML(button_where,button_code);hide_show_letter_img();
}

if (b!==null){
b.onclick=function(e){var i=e.target.innerText;
var t=button_to,f=button_from;
if(i.indexOf(button_search)>-1){f=button_to;t=button_from;}
e.target.innerText=i.replace(f,t);hide_show_letter_img();
};}
}

document.addEventListener("DOMContentLoaded", function(){init_find_place();});
init_find_place();
window.onload=function(){init_find_place();var t = setInterval(function(){init_find_place();},main_interval_reload);
document.addEventListener('DOMNodeInserted',function(e){init_find_place();});
};
})();<commit_msg>mail.yandex.ru imgs<commit_after>// ==UserScript==
// @name       *mail.yandex.ru blocks all images from amazon, ebay, optional load images by click
// @namespace  http://gubnota.github.io/fenki_js_helpers/plugin/monkey/mail_yandex_ru_adds/
// @version    0.0.5
// @downloadURL http://gubnota.github.io/fenki_js_helpers/plugin/monkey/mail_yandex_ru_adds/hide_img.user.js
// @description removes adds block(s) in mail.yeah.net
// @include      http://*mail.yandex.*/*
// @include      https://*mail.yandex.*/*
// @copyright  2016+, Vladislav Muravyev
// @author Vladislav Muravyev
// @grant          none
// @icon http://gubnota.github.io/fenki_js_helpers/plugin/monkey/mail_yandex_ru_adds/yandex.ico
// @run-at document-start
// ==/UserScript==
(function(){

var imgscope='.mail-Message-Body *',/*image searching scope*/
empty_dot="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==",/*.placedb-letter*/
click_handlers='.ns-view-messages-item',/*on click which items to (re)-run hide images*/
insert_button_place='.ns-view-message-toolbar',/*where to insert show images button*/
button_id='show_img',/*button id to show images*/
button_code='Показать картинки',
button_where='afterBegin',
button_from='Показ',
button_to='Спрят',
button_search='з',
main_interval_reload=2000;
function bgimg_handler(el){
if(el.style.backgroundImage){
	if (!el.getAttribute('old-bgimg')){
	el.setAttribute('old-bgimg',el.style.backgroundImage.replace(/(.*)/,'/*$1*/'));
	el.style.backgroundImage="url("+empty_dot+")";
	}
	else{
	el.style.backgroundImage=el.getAttribute('old-bgimg').replace(/\/\*(.*)\*\//,'$1');
	el.removeAttribute('old-bgimg');
	}
}
}
function attr_handler(el,attr){
	attr.forEach(function(at){
	if (!el.getAttribute('old-'+at) && el.getAttribute(at)){
	el.setAttribute('old-'+at,el.getAttribute(at));
	el.setAttribute(at,empty_dot);
	}
	else if (el.getAttribute('old-'+at)){
	el.setAttribute(at,el.getAttribute('old-'+at));
	el.removeAttribute('old-'+at);
	}
	});
}

function hide_show_letter_img(){
[].forEach.call(document.querySelectorAll(imgscope),function(el) {
bgimg_handler(el);/*bg-img*/

if (el.nodeName=='IMG') {
	bgimg_handler(el);
	attr_handler(el,['src','srcset']);
}/*img src*/
});}

function init_find_place(){
var a = document.querySelectorAll(insert_button_place);
var b=document.getElementById(button_id);

if (b === null && a.length>0){
a[0].insertAdjacentHTML(button_where,button_code);hide_show_letter_img();
}

if (b!==null){
b.onclick=function(e){var i=e.target.innerText;
var t=button_to,f=button_from;
if(i.indexOf(button_search)>-1){f=button_to;t=button_from;}
e.target.innerText=i.replace(f,t);hide_show_letter_img();
};}
}

document.addEventListener("DOMContentLoaded", function(){init_find_place();});
init_find_place();
window.onload=function(){init_find_place();var t = setInterval(function(){init_find_place();},main_interval_reload);
document.addEventListener('DOMNodeInserted',function(e){init_find_place();});
};
})();<|endoftext|>


<commit_before>"use strict";

const THRESHOLDS = {
  CONSUMER: {
    ERRORS: 5,
    LAG: 1000,
    STALL_LAG: 10,
    MIN_MESSAGES: 1
  },
  PRODUCER: {
    ERRORS: 4,
    MIN_MESSAGES: 1
  }
};

const STATES = {
  DIS_ANALYTICS: -4,
  NO_ANALYTICS: -3,
  UNKNOWN: -2,
  UNCONNECTED: -1,
  HEALTHY: 0,
  RISK: 1,
  WARNING: 2,
  CRITICAL: 3
};

const MESSAGES = {
  DIS_ANALYTICS: "Analytics are disabled, cannot measure required parameters. Please enable.",
  NO_ANALYTICS: "Analytics have not yet run, checks will be available after first run.",
  UNKNOWN: "State is unknown.",
  UNCONNECTED: "The client is not connected.",
  HEALTHY: "No problems detected, client is healthy."
};

/**
 * little pojso class around the check object
 */
class Check {

  /**
   * creates a new instance
   * @param {number} status - status code
   * @param {Array|string} message - message/s, pass an empty array to initialise clean
   */
  constructor(status = STATES.HEALTHY, message = MESSAGES.HEALTHY){
    this.status = status;
    this.messages = Array.isArray(message) ? message : [message];
  }

  /**
   *
   * @param {number} status - new status code
   * @returns {boolean}
   */
  changeStatus(status = STATES.UNKNOWN){

    if(status > this.status){
      this.status = status;
      return true;
    }

    return false;
  }

  /**
   * adds a message to the check
   * @param {string} message - string message to attach
   * @returns {number}
   */
  add(message = MESSAGES.UNKNOWN){
    return this.messages.push(message);
  }
}

/**
 * health parent class
 */
class Health {

  /**
   * creates a new instance
   * @param {NConsumer|NProducer} client
   */
  constructor(client){
    this.client = client;

    //make them accessable
    this.STATES = STATES;
    this.MESSAGES = MESSAGES;
  }

  /**
   * returns a new check instance
   * @param {number} status
   * @param {Array|string} message
   */
  createCheck(status, message){
    return new Check(status, message);
  }
}

/**
 * health check adapted for NConsumers
 * @extends Health
 */
class ConsumerHealth extends Health {

  /**
   * creates a new instance
   * @param {NConsumer} nconsumer
   */
  constructor(nconsumer){
    super(nconsumer);
  }

  /**
   * runs the health check
   * @async
   * @returns {Promise.<Check>}
   */
  async check(){

    /* ### preparation ### */

    if(!this.client.consumer){
      return super.createCheck(STATES.UNCONNECTED, MESSAGES.UNCONNECTED);
    }

    if(!this.client._analytics){
      return super.createCheck(STATES.DIS_ANALYTICS, MESSAGES.DIS_ANALYTICS);
    }

    const analytics = this.client._analytics.getLastResult();

    if(!analytics){
      return super.createCheck(STATES.NO_ANALYTICS, MESSAGES.NO_ANALYTICS);
    }

    /* ### eof preparation ### */

    const check = new Check(STATES.HEALTHY, []);

    if(analytics.errors !== null && analytics.errors >= THRESHOLDS.CONSUMER.ERRORS){
      check.changeStatus(STATES.CRITICAL);
      check.add(MESSAGES.ERRORS);
    }

    if(analytics.largestLag !== null && analytics.largestLag.highDistance &&
        analytics.largestLag.highDistance > THRESHOLDS.CONSUMER.LAG){
      check.changeStatus(STATES.WARNING);
      check.add(`Lag exceeds threshold with a lag of ${analytics.largestLag.highDistance}` +
        ` on ${analytics.largestLag.topic}:${analytics.largestLag.partition}.`);
    }

    if(analytics.lagChange !== null && Object.keys(analytics.lagChange.stallLags).length > THRESHOLDS.CONSUMER.STALL_LAG){
      check.changeStatus(STATES.RISK);
      check.add(`Amount of stall lags exceeds threshold with ${Object.keys(analytics.lagChange.stallLags).length} unchanged lagging offsets.`);
    }

    if(analytics.consumed !== null && analytics.consumed < THRESHOLDS.CONSUMER.MIN_MESSAGES){
      check.changeStatus(STATES.RISK);
      check.add(`Amount of consumed messages is low ${analytics.consumed}.`);
    }

    if(check.status === STATES.HEALTHY){
      check.add(MESSAGES.HEALTHY);
      check.add(`Consumed ${analytics.consumed} message/s in the last interval, with ${analytics.errors} errors.`);
    }

    return check;
  }
}

/**
 * health check adapted for NProducers
 * @extends Health
 */
class ProducerHealth extends Health {

  /**
   * creates a new instance
   * @param {NProducer} nproducer
   */
  constructor(nproducer){
    super(nproducer);
  }

  /**
   * runs the health check
   * @async
   * @returns {Promise.<Check>}
   */
  async check(){

    /* ### preparation ### */

    if(!this.client.producer){
      return super.createCheck(STATES.UNCONNECTED, MESSAGES.UNCONNECTED);
    }

    if(!this.client._analytics){
      return super.createCheck(STATES.DIS_ANALYTICS, MESSAGES.DIS_ANALYTICS);
    }

    const analytics = this.client._analytics.getLastResult();

    if(!analytics){
      return super.createCheck(STATES.NO_ANALYTICS, MESSAGES.NO_ANALYTICS);
    }

    /* ### eof preparation ### */

    const check = new Check(STATES.HEALTHY, []);

    if(analytics.errors !== null && analytics.errors >= THRESHOLDS.PRODUCER.ERRORS){
      check.changeStatus(STATES.CRITICAL);
      check.add(MESSAGES.ERRORS);
    }

    if(analytics.produced !== null && analytics.produced < THRESHOLDS.PRODUCER.MIN_MESSAGES){
      check.changeStatus(STATES.RISK);
      check.add(`Amount of produced messages is low ${analytics.produced}.`);
    }

    if(check.status === STATES.HEALTHY){
      check.add(MESSAGES.HEALTHY);
      check.add(`Produced ${analytics.produced} message/s in the last interval, with ${analytics.errors} errors.`);
    }

    return check;
  }
}

module.exports = {
  ConsumerHealth,
  ProducerHealth
};
<commit_msg>fixed bug in health<commit_after>"use strict";

const THRESHOLDS = {
  CONSUMER: {
    ERRORS: 5,
    LAG: 1000,
    STALL_LAG: 10,
    MIN_MESSAGES: 1
  },
  PRODUCER: {
    ERRORS: 4,
    MIN_MESSAGES: 1
  }
};

const STATES = {
  DIS_ANALYTICS: -4,
  NO_ANALYTICS: -3,
  UNKNOWN: -2,
  UNCONNECTED: -1,
  HEALTHY: 0,
  RISK: 1,
  WARNING: 2,
  CRITICAL: 3
};

const MESSAGES = {
  DIS_ANALYTICS: "Analytics are disabled, cannot measure required parameters. Please enable.",
  NO_ANALYTICS: "Analytics have not yet run, checks will be available after first run.",
  UNKNOWN: "State is unknown.",
  UNCONNECTED: "The client is not connected.",
  HEALTHY: "No problems detected, client is healthy."
};

/**
 * little pojso class around the check object
 */
class Check {

  /**
   * creates a new instance
   * @param {number} status - status code
   * @param {Array|string} message - message/s, pass an empty array to initialise clean
   */
  constructor(status = STATES.HEALTHY, message = MESSAGES.HEALTHY){
    this.status = status;
    this.messages = Array.isArray(message) ? message : [message];
  }

  /**
   *
   * @param {number} status - new status code
   * @returns {boolean}
   */
  changeStatus(status = STATES.UNKNOWN){

    if(status > this.status){
      this.status = status;
      return true;
    }

    return false;
  }

  /**
   * adds a message to the check
   * @param {string} message - string message to attach
   * @returns {number}
   */
  add(message = MESSAGES.UNKNOWN){
    return this.messages.push(message);
  }
}

/**
 * health parent class
 */
class Health {

  /**
   * creates a new instance
   * @param {NConsumer|NProducer} client
   */
  constructor(client){
    this.client = client;

    //make them accessable
    this.STATES = STATES;
    this.MESSAGES = MESSAGES;
  }

  /**
   * returns a new check instance
   * @param {number} status
   * @param {Array|string} message
   */
  createCheck(status, message){
    return new Check(status, message);
  }
}

/**
 * health check adapted for NConsumers
 * @extends Health
 */
class ConsumerHealth extends Health {

  /**
   * creates a new instance
   * @param {NConsumer} nconsumer
   */
  constructor(nconsumer){
    super(nconsumer);
  }

  /**
   * runs the health check
   * @async
   * @returns {Promise.<Check>}
   */
  async check(){

    /* ### preparation ### */

    if(!this.client.consumer){
      return super.createCheck(STATES.UNCONNECTED, MESSAGES.UNCONNECTED);
    }

    if(!this.client._analytics){
      return super.createCheck(STATES.DIS_ANALYTICS, MESSAGES.DIS_ANALYTICS);
    }

    const analytics = this.client._analytics.getLastResult();

    if(!analytics){
      return super.createCheck(STATES.NO_ANALYTICS, MESSAGES.NO_ANALYTICS);
    }

    /* ### eof preparation ### */

    const check = new Check(STATES.HEALTHY, []);

    if(analytics.errors !== null && analytics.errors >= THRESHOLDS.CONSUMER.ERRORS){
      check.changeStatus(STATES.CRITICAL);
      check.add(MESSAGES.ERRORS);
    }

    if(analytics.largestLag !== null && analytics.largestLag.highDistance &&
        analytics.largestLag.highDistance > THRESHOLDS.CONSUMER.LAG){
      check.changeStatus(STATES.WARNING);
      check.add(`Lag exceeds threshold with a lag of ${analytics.largestLag.highDistance}` +
        ` on ${analytics.largestLag.topic}:${analytics.largestLag.partition}.`);
    }

    if(analytics.lagChange !== null && typeof analytics.lagChange.stallLags === "object" &&
        Object.keys(analytics.lagChange.stallLags).length > THRESHOLDS.CONSUMER.STALL_LAG){
      check.changeStatus(STATES.RISK);
      check.add(`Amount of stall lags exceeds threshold with ${Object.keys(analytics.lagChange.stallLags).length} unchanged lagging offsets.`);
    }

    if(analytics.consumed !== null && analytics.consumed < THRESHOLDS.CONSUMER.MIN_MESSAGES){
      check.changeStatus(STATES.RISK);
      check.add(`Amount of consumed messages is low ${analytics.consumed}.`);
    }

    if(check.status === STATES.HEALTHY){
      check.add(MESSAGES.HEALTHY);
      check.add(`Consumed ${analytics.consumed} message/s in the last interval, with ${analytics.errors} errors.`);
    }

    return check;
  }
}

/**
 * health check adapted for NProducers
 * @extends Health
 */
class ProducerHealth extends Health {

  /**
   * creates a new instance
   * @param {NProducer} nproducer
   */
  constructor(nproducer){
    super(nproducer);
  }

  /**
   * runs the health check
   * @async
   * @returns {Promise.<Check>}
   */
  async check(){

    /* ### preparation ### */

    if(!this.client.producer){
      return super.createCheck(STATES.UNCONNECTED, MESSAGES.UNCONNECTED);
    }

    if(!this.client._analytics){
      return super.createCheck(STATES.DIS_ANALYTICS, MESSAGES.DIS_ANALYTICS);
    }

    const analytics = this.client._analytics.getLastResult();

    if(!analytics){
      return super.createCheck(STATES.NO_ANALYTICS, MESSAGES.NO_ANALYTICS);
    }

    /* ### eof preparation ### */

    const check = new Check(STATES.HEALTHY, []);

    if(analytics.errors !== null && analytics.errors >= THRESHOLDS.PRODUCER.ERRORS){
      check.changeStatus(STATES.CRITICAL);
      check.add(MESSAGES.ERRORS);
    }

    if(analytics.produced !== null && analytics.produced < THRESHOLDS.PRODUCER.MIN_MESSAGES){
      check.changeStatus(STATES.RISK);
      check.add(`Amount of produced messages is low ${analytics.produced}.`);
    }

    if(check.status === STATES.HEALTHY){
      check.add(MESSAGES.HEALTHY);
      check.add(`Produced ${analytics.produced} message/s in the last interval, with ${analytics.errors} errors.`);
    }

    return check;
  }
}

module.exports = {
  ConsumerHealth,
  ProducerHealth
};
<|endoftext|>


<commit_before>'use strict';

var metadataEditorApp = angular
    .module('metadataEditor', ['ngRoute', 'ui.date', 'ngMap', 'ngAnimate', 'ui.router', 'ngRoute'])
    .config(function($compileProvider, $stateProvider, $urlRouterProvider, $routeProvider, $locationProvider) {
	// $compileProvider.aHrefSanitizationWhitelist(/localhost:/);

	var partialsPrefix = "partials/form/";

	//Comment out line above, uncomment line below to use system in Drupal framwork on development server
	//var partialsPrefix = "frontend/partials/form/";

	$stateProvider
	    .state('form', {
		templateURl: 'partials/iso.html'
	    })
	    .state('form.setup', {
		templateUrl: partialsPrefix + 'setup.html'
	    })
	    .state('form.basic', {
		templateUrl:  partialsPrefix + 'basic.html'
	    })
	    .state('form.detailed', {
		templateUrl:  partialsPrefix + 'detailed.html'
	    })
	    .state('form.dataFormats', {
		templateUrl:  partialsPrefix + 'isoDataFormats.html'
	    })
	    .state('form.onlineResourcesAndRestrictions', {
		templateUrl:  partialsPrefix + 'onlineResourcesAndRestrictions.html'
	    })
	    .state('form.spatialExtent', {
		templateUrl:  partialsPrefix + 'spatialExtent.html'
	    })
	    .state('form.temporalExtent', {
		templateUrl:  partialsPrefix + 'isoTemporalExtent.html'
	    })
	    .state('form.review', {
		templateUrl:  partialsPrefix + 'review.html'
	    })
	    .state('form.termsConditions', {
		templateUrl:  partialsPrefix + 'termsConditions.html'
	    })
	    .state('form.disclaimer', {
		templateUrl:  partialsPrefix + 'disclaimer.html'
	    })
	    .state('form.sensitiveInformation', {
		templateUrl:  partialsPrefix + 'sensitiveInformation.html'
	    })
	    .state('form.optionsAndDisclaimer', {
		templateUrl:  partialsPrefix + 'optionsAndDisclaimer.html'
	    })
	    .state('form.contacts', {
		templateUrl:  partialsPrefix + 'contacts.html'
	    })

	    .state('dublinForm',{
		templateURL: 'partials/dublin.html'
	    })

	    .state('dublinForm.setup', {
		templateUrl:  partialsPrefix + 'setup.html'
	    })
	    .state('dublinForm.basic', {
		templateUrl:  partialsPrefix + 'basic.html'
	    })
	    .state('dublinForm.dataFormats', {
		templateUrl:  partialsPrefix + 'dublinDataFormats.html'
	    })
	    .state('dublinForm.onlineResourcesAndRestrictions', {
		templateUrl:  partialsPrefix + 'onlineResourcesAndRestrictions.html'
	    })
	    .state('dublinForm.spatialExtent', {
		templateUrl:  partialsPrefix + 'spatialExtent.html'
	    })
	    .state('dublinForm.temporalExtent', {
		templateUrl:  partialsPrefix + 'dublinTemporalExtent.html'
	    })
	    .state('dublinForm.review', {
		templateUrl:  partialsPrefix + 'review.html'
	    })
	    .state('dublinForm.disclaimer', {
		templateUrl:  partialsPrefix + 'disclaimer.html'
	    })
	    .state('dublinForm.optionsAndDisclaimer', {
		templateUrl:  partialsPrefix + 'optionsAndDisclaimer.html'
	    })
	    .state('dublinForm.contacts', {
		templateUrl:  partialsPrefix + 'contacts.html'
	    });

 	$urlRouterProvider
	    .when(/iso/i, '/iso')
	    .when(/dublin/i, '/dublin')
	    .otherwise('/iso');
})
.constant('formOptions',  {

 	topicCategoryChoices: ['biota', 'boundaries',
   'climatologyMeteorologyAtmosphere', 'economy', 'elevation',
   'environment', 'farming', 'geoscientificInformation', 'health',
   'imageryBaseMapsEarthCover', 'inlandWaters', 'location',
   'intelligenceMilitary', 'oceans', 'planningCadastre', 'society',
   'structure', 'transportation',
   'utilitiesCommunication'],

 knownDataFormats: ["ASCII", "csv", "DLG", "docx", "DRG", "DWG", "eps",
      "ERDAS", "Esri file GDB", "Esri grid", "Esri personal GDB","Esri TIN", "FASTA", "FASTQ", "GenBank",
      "GeoJSON", "GeoTIFF", "GML", "HDF", "jpeg", "KML", "LAS", "mp3",
      "MrSID", "netCDF", "pdf", "php", "png", "py", "R", "SDXF", "Shapefile",
      "SPSS", "Stata", "Tab", "tiff", "txt", "VBS", "wav", "xls", "xlsx",
      "xml"],

	spatialDataOptions: ["vector", "grid", "table or text",
      "triangulated irregular network", "stereographic imaging",
      "video recording of a scene"],

	hierarchyLevels: ["dataset", "series"],

	statusChoicesIsoMap:
    {
        'completed': 'completed',
        'continually updated': 'onGoing',
        'in process': 'underDevelopment',
        'planned': 'planned',
        'needs to be generated or updated': 'required',
        'stored in an offline facility': 'historicalArchive',
        'no longer valid': 'obsolete'
    },

	updateFrequencyChoicesMap:
    {
        'continual': 'continual',
        'daily': 'daily',
        'weekly': 'weekly',
        'fortnightly': 'fortnightly',
        'monthly': 'monthly',
        'quarterly': 'quarterly',
        'biannually': 'biannually',
        'annually': 'annually',
        'as needed': 'asNeeded',
        'irregular': 'irregular',
        'not planned': 'notPlanned',
        'unknown': 'unknown'
    },

	orderedContactFields: ['name', 'email', 'org', 'address', 'city',
				       'state', 'zipcode', 'country', 'phone'],

	cfieldsMap:
    {
        'name': 'Name',
        'email': 'Email',
        'org': 'Organization',
        'address': 'Address',
        'city': 'City',
        'state': 'State',
        'zipcode': 'Zip Code',
        'country': 'Country',
        'phone': 'Phone'
    }
}
).constant('emptyContact', {
      'name': '', 'email': '', 'org': '', 'address': '',
      'city': '', 'state': '', 'zipcode': '', 'country': '', 'phone': ''
})
    .run(function($rootScope, hostname){
	$rootScope.$on('$stateChangeStart', function(event, toState, toParams) {
	    //If app is not a local instance, and in Drupal, then we need to add "frontend/" to the path
	    //for states.
	    if(hostname.indexOf('localhost') == -1)
		if(toState.templateUrl.indexOf("frontend/") == -1)
		    toState.templateUrl = "frontend/" + toState.templateUrl;
	})
    });
<commit_msg>Took out commented out code in app.js that was for different path for states in Drupal install. System now automatically changes state templateUrl paths for states at runtime to account for different paths used for local and Drupal installs.<commit_after>'use strict';

var metadataEditorApp = angular
    .module('metadataEditor', ['ngRoute', 'ui.date', 'ngMap', 'ngAnimate', 'ui.router', 'ngRoute'])
    .config(function($compileProvider, $stateProvider, $urlRouterProvider, $routeProvider, $locationProvider) {
	// $compileProvider.aHrefSanitizationWhitelist(/localhost:/);

	var partialsPrefix = "partials/form/";

	$stateProvider
	    .state('form', {
		templateURl: 'partials/iso.html'
	    })
	    .state('form.setup', {
		templateUrl: partialsPrefix + 'setup.html'
	    })
	    .state('form.basic', {
		templateUrl:  partialsPrefix + 'basic.html'
	    })
	    .state('form.detailed', {
		templateUrl:  partialsPrefix + 'detailed.html'
	    })
	    .state('form.dataFormats', {
		templateUrl:  partialsPrefix + 'isoDataFormats.html'
	    })
	    .state('form.onlineResourcesAndRestrictions', {
		templateUrl:  partialsPrefix + 'onlineResourcesAndRestrictions.html'
	    })
	    .state('form.spatialExtent', {
		templateUrl:  partialsPrefix + 'spatialExtent.html'
	    })
	    .state('form.temporalExtent', {
		templateUrl:  partialsPrefix + 'isoTemporalExtent.html'
	    })
	    .state('form.review', {
		templateUrl:  partialsPrefix + 'review.html'
	    })
	    .state('form.termsConditions', {
		templateUrl:  partialsPrefix + 'termsConditions.html'
	    })
	    .state('form.disclaimer', {
		templateUrl:  partialsPrefix + 'disclaimer.html'
	    })
	    .state('form.sensitiveInformation', {
		templateUrl:  partialsPrefix + 'sensitiveInformation.html'
	    })
	    .state('form.optionsAndDisclaimer', {
		templateUrl:  partialsPrefix + 'optionsAndDisclaimer.html'
	    })
	    .state('form.contacts', {
		templateUrl:  partialsPrefix + 'contacts.html'
	    })

	    .state('dublinForm',{
		templateURL: 'partials/dublin.html'
	    })

	    .state('dublinForm.setup', {
		templateUrl:  partialsPrefix + 'setup.html'
	    })
	    .state('dublinForm.basic', {
		templateUrl:  partialsPrefix + 'basic.html'
	    })
	    .state('dublinForm.dataFormats', {
		templateUrl:  partialsPrefix + 'dublinDataFormats.html'
	    })
	    .state('dublinForm.onlineResourcesAndRestrictions', {
		templateUrl:  partialsPrefix + 'onlineResourcesAndRestrictions.html'
	    })
	    .state('dublinForm.spatialExtent', {
		templateUrl:  partialsPrefix + 'spatialExtent.html'
	    })
	    .state('dublinForm.temporalExtent', {
		templateUrl:  partialsPrefix + 'dublinTemporalExtent.html'
	    })
	    .state('dublinForm.review', {
		templateUrl:  partialsPrefix + 'review.html'
	    })
	    .state('dublinForm.disclaimer', {
		templateUrl:  partialsPrefix + 'disclaimer.html'
	    })
	    .state('dublinForm.optionsAndDisclaimer', {
		templateUrl:  partialsPrefix + 'optionsAndDisclaimer.html'
	    })
	    .state('dublinForm.contacts', {
		templateUrl:  partialsPrefix + 'contacts.html'
	    });

 	$urlRouterProvider
	    .when(/iso/i, '/iso')
	    .when(/dublin/i, '/dublin')
	    .otherwise('/iso');
})
.constant('formOptions',  {

 	topicCategoryChoices: ['biota', 'boundaries',
   'climatologyMeteorologyAtmosphere', 'economy', 'elevation',
   'environment', 'farming', 'geoscientificInformation', 'health',
   'imageryBaseMapsEarthCover', 'inlandWaters', 'location',
   'intelligenceMilitary', 'oceans', 'planningCadastre', 'society',
   'structure', 'transportation',
   'utilitiesCommunication'],

 knownDataFormats: ["ASCII", "csv", "DLG", "docx", "DRG", "DWG", "eps",
      "ERDAS", "Esri file GDB", "Esri grid", "Esri personal GDB","Esri TIN", "FASTA", "FASTQ", "GenBank",
      "GeoJSON", "GeoTIFF", "GML", "HDF", "jpeg", "KML", "LAS", "mp3",
      "MrSID", "netCDF", "pdf", "php", "png", "py", "R", "SDXF", "Shapefile",
      "SPSS", "Stata", "Tab", "tiff", "txt", "VBS", "wav", "xls", "xlsx",
      "xml"],

	spatialDataOptions: ["vector", "grid", "table or text",
      "triangulated irregular network", "stereographic imaging",
      "video recording of a scene"],

	hierarchyLevels: ["dataset", "series"],

	statusChoicesIsoMap:
    {
        'completed': 'completed',
        'continually updated': 'onGoing',
        'in process': 'underDevelopment',
        'planned': 'planned',
        'needs to be generated or updated': 'required',
        'stored in an offline facility': 'historicalArchive',
        'no longer valid': 'obsolete'
    },

	updateFrequencyChoicesMap:
    {
        'continual': 'continual',
        'daily': 'daily',
        'weekly': 'weekly',
        'fortnightly': 'fortnightly',
        'monthly': 'monthly',
        'quarterly': 'quarterly',
        'biannually': 'biannually',
        'annually': 'annually',
        'as needed': 'asNeeded',
        'irregular': 'irregular',
        'not planned': 'notPlanned',
        'unknown': 'unknown'
    },

	orderedContactFields: ['name', 'email', 'org', 'address', 'city',
				       'state', 'zipcode', 'country', 'phone'],

	cfieldsMap:
    {
        'name': 'Name',
        'email': 'Email',
        'org': 'Organization',
        'address': 'Address',
        'city': 'City',
        'state': 'State',
        'zipcode': 'Zip Code',
        'country': 'Country',
        'phone': 'Phone'
    }
}
).constant('emptyContact', {
      'name': '', 'email': '', 'org': '', 'address': '',
      'city': '', 'state': '', 'zipcode': '', 'country': '', 'phone': ''
})
.run(function($rootScope, hostname){
    $rootScope.$on('$stateChangeStart', function(event, toState, toParams) {
	//If app is not a local instance, and in Drupal, then we need to add "frontend/" to the path
	//for states.
	if(hostname.indexOf('localhost') == -1)
	    if(toState.templateUrl.indexOf("frontend/") == -1)
		toState.templateUrl = "frontend/" + toState.templateUrl;
    })
});
<|endoftext|>


<commit_before><commit_msg>Added a lastDown property and basic functionality for a keydow.<commit_after><|endoftext|>


<commit_before>import WRISerializer from 'wri-json-api-serializer';

// utils
import { WRIAPI } from 'utils/axios';
import { logger } from 'utils/logs';

/**
 * Retrieve all collections of the user
 * @param {*} token User's token
 * @param {*} params Request optional parameters
 */
export const fetchAllCollections = (
  token,
  params = {
    env: process.env.API_ENV,
    application: process.env.APPLICATIONS
  }
) => {
  logger.info('Fetch all collections');
  WRIAPI.get('collection', {
    headers: {
      Authorization: token,
      'Upgrade-Insecure-Requests': 1
    },
    params
  })
    .then(response => WRISerializer(response.data))
    .catch(({ response }) => {
      const { status, statusText } = response;
      logger.error(`Error fetching all collections: ${status}: ${statusText}`);
      throw new Error(`Error fetching all collections: ${status}: ${statusText}`);
    });
};
/**
 * Retrieve data of a specific collection
 * @param {*} token User's token
 * @param {*} collectionId Id of the collection we are asking for.
 * @param {*} params Request parameters
 */
export const fetchCollection = (
  token,
  collectionId,
  params = {
    env: process.env.API_ENV,
    application: process.env.APPLICATIONS
  }
) => {
  logger.info(`Fetch collection ${collectionId}`);
  return WRIAPI.get(`collection/${collectionId}`, {
    headers: {
      Authorization: token,
      'Upgrade-Insecure-Requests': 1
    },
    params
  })
    .then(response => WRISerializer(response.data))
    .catch(({ response }) => {
      const { status, statusText } = response;
      logger.error(`Error fetching collection ${collectionId}: ${status}: ${statusText}`);
      throw new Error(`Error fetching collection ${collectionId}: ${status}: ${statusText}`);
    });
};

/**
 * Creates a new collection attached to the current user
 * @param {*} token User's token
 * @param {*} data collection data
 */
export const createCollection = (token, data = {}) => {
  logger.info('Create collection');
  return WRIAPI.post(`${process.env.WRI_API_URL}/collection`, data, {
    headers: {
      'Content-Type': 'application/json',
      Authorization: token
    }
  })
    .then(response => WRISerializer(response.data))
    .catch(({ response }) => {
      const { status, statusText } = response;
      logger.error(`Error creating collection: ${status}: ${statusText}`);
      throw new Error(`Error creating collection: ${status}: ${statusText}`);
    });
};

/**
 * Deletes an existing collection attached to the current user
 * @param {*} token User's token
 * @param {*} collectionId Id of the collection to be removed
 */
export const deleteCollection = (token, collectionId) => {
  logger.info(`Delete collection ${collectionId}`);
  return WRIAPI.delete(`collection/${collectionId}`, { headers: { Authorization: token } })
    .then(response => WRISerializer(response.data))
    .catch(({ response }) => {
      const { status, statusText } = response;
      logger.error(`Error deleting collection ${collectionId}: ${status}: ${statusText}`);
      throw new Error(`Error deleting collection ${collectionId}: ${status}: ${statusText}`);
    });
};

/**
 * Update an existing collection attached to the current user
 * @param {*} token User's token
 * @param {*} collectionId Id of the collection to be edited
 * @param {*} data Data to be updated
 */
export const updateCollection = (token, collectionId, data) => {
  logger.info(`Update collection ${collectionId}`);
  return WRIAPI.patch(`collection/${collectionId}`, data, {
    headers: {
      'content-type': 'application/json',
      Authorization: token
    }
  })
    .then(response => WRISerializer(response.data))
    .catch(({ response }) => {
      const { status, statusText } = response;
      logger.error(`Error updating collection ${collectionId}: ${status}: ${statusText}`);
      throw new Error(`Error updating collection ${collectionId}: ${status}: ${statusText}`);
    });
};

/* Resources management  */

/**
 *
 * @param {*} token User's token
 * @param {*} collectionId Id of the collection to be edited
 * @param {*} resource Resource to be addded to the collection
 */
export const addResourceToCollection = (token, collectionId, resource = []) => {
  logger.info(`Add resource to collection ${collectionId}`);
  return WRIAPI.post(
    `collection/${collectionId}/resource`,
    { ...resource },
    {
      headers: {
        'Content-Type': 'application/json',
        Authorization: token
      }
    }
  )
    .then(response => WRISerializer(response.data))
    .catch(({ response }) => {
      const { status, statusText } = response;
      logger.error(`Error adding resource to collection ${collectionId}: ${status}: ${statusText}`);
      throw new Error(
        `Error adding resource to collection ${collectionId}: ${status}: ${statusText}`
      );
    });
};

/**
 *
 * @param {*} token User's token
 * @param {*} collectionId Id of the collection to be edited
 * @param {*} resource Resource to be removed from the collection
 */
export const removeResourceFromCollection = (token, collectionId, resource = []) => {
  logger.info(`Remove resource from collection ${collectionId}`);
  const { type, id } = resource;
  return WRIAPI.delete(`collection/${collectionId}/resource/${type}/${id}`, { headers: { Authorization: token } })
    .then(response => WRISerializer(response.data))
    .catch(({ response }) => {
      const { status, statusText } = response;
      logger.error(
        `Error removing resource from collection ${collectionId}: ${status}: ${statusText}`
      );
      throw new Error(
        `Error removing resource from collection ${collectionId}: ${status}: ${statusText}`
      );
    });
};

export default {
  fetchAllCollections,
  fetchCollection,
  createCollection,
  deleteCollection,
  updateCollection,
  addResourceToCollection,
  removeResourceFromCollection
};
<commit_msg>fix for fetchAllCollections<commit_after>import WRISerializer from 'wri-json-api-serializer';

// utils
import { WRIAPI } from 'utils/axios';
import { logger } from 'utils/logs';

/**
 * Retrieve all collections of the user
 * @param {*} token User's token
 * @param {*} params Request optional parameters
 */
export const fetchAllCollections = (
  token,
  params = {
    env: process.env.API_ENV,
    application: process.env.APPLICATIONS
  }
) => {
  logger.info('Fetch all collections');
  return WRIAPI.get('collection', {
    headers: {
      Authorization: token,
      'Upgrade-Insecure-Requests': 1
    },
    params
  })
    .then(response => WRISerializer(response.data))
    .catch(({ response }) => {
      const { status, statusText } = response;
      logger.error(`Error fetching all collections: ${status}: ${statusText}`);
      throw new Error(`Error fetching all collections: ${status}: ${statusText}`);
    });
};
/**
 * Retrieve data of a specific collection
 * @param {*} token User's token
 * @param {*} collectionId Id of the collection we are asking for.
 * @param {*} params Request parameters
 */
export const fetchCollection = (
  token,
  collectionId,
  params = {
    env: process.env.API_ENV,
    application: process.env.APPLICATIONS
  }
) => {
  logger.info(`Fetch collection ${collectionId}`);
  return WRIAPI.get(`collection/${collectionId}`, {
    headers: {
      Authorization: token,
      'Upgrade-Insecure-Requests': 1
    },
    params
  })
    .then(response => WRISerializer(response.data))
    .catch(({ response }) => {
      const { status, statusText } = response;
      logger.error(`Error fetching collection ${collectionId}: ${status}: ${statusText}`);
      throw new Error(`Error fetching collection ${collectionId}: ${status}: ${statusText}`);
    });
};

/**
 * Creates a new collection attached to the current user
 * @param {*} token User's token
 * @param {*} data collection data
 */
export const createCollection = (token, data = {}) => {
  logger.info('Create collection');
  return WRIAPI.post(`${process.env.WRI_API_URL}/collection`, data, {
    headers: {
      'Content-Type': 'application/json',
      Authorization: token
    }
  })
    .then(response => WRISerializer(response.data))
    .catch(({ response }) => {
      const { status, statusText } = response;
      logger.error(`Error creating collection: ${status}: ${statusText}`);
      throw new Error(`Error creating collection: ${status}: ${statusText}`);
    });
};

/**
 * Deletes an existing collection attached to the current user
 * @param {*} token User's token
 * @param {*} collectionId Id of the collection to be removed
 */
export const deleteCollection = (token, collectionId) => {
  logger.info(`Delete collection ${collectionId}`);
  return WRIAPI.delete(`collection/${collectionId}`, { headers: { Authorization: token } })
    .then(response => WRISerializer(response.data))
    .catch(({ response }) => {
      const { status, statusText } = response;
      logger.error(`Error deleting collection ${collectionId}: ${status}: ${statusText}`);
      throw new Error(`Error deleting collection ${collectionId}: ${status}: ${statusText}`);
    });
};

/**
 * Update an existing collection attached to the current user
 * @param {*} token User's token
 * @param {*} collectionId Id of the collection to be edited
 * @param {*} data Data to be updated
 */
export const updateCollection = (token, collectionId, data) => {
  logger.info(`Update collection ${collectionId}`);
  return WRIAPI.patch(`collection/${collectionId}`, data, {
    headers: {
      'content-type': 'application/json',
      Authorization: token
    }
  })
    .then(response => WRISerializer(response.data))
    .catch(({ response }) => {
      const { status, statusText } = response;
      logger.error(`Error updating collection ${collectionId}: ${status}: ${statusText}`);
      throw new Error(`Error updating collection ${collectionId}: ${status}: ${statusText}`);
    });
};

/* Resources management  */

/**
 *
 * @param {*} token User's token
 * @param {*} collectionId Id of the collection to be edited
 * @param {*} resource Resource to be addded to the collection
 */
export const addResourceToCollection = (token, collectionId, resource = []) => {
  logger.info(`Add resource to collection ${collectionId}`);
  return WRIAPI.post(
    `collection/${collectionId}/resource`,
    { ...resource },
    {
      headers: {
        'Content-Type': 'application/json',
        Authorization: token
      }
    }
  )
    .then(response => WRISerializer(response.data))
    .catch(({ response }) => {
      const { status, statusText } = response;
      logger.error(`Error adding resource to collection ${collectionId}: ${status}: ${statusText}`);
      throw new Error(
        `Error adding resource to collection ${collectionId}: ${status}: ${statusText}`
      );
    });
};

/**
 *
 * @param {*} token User's token
 * @param {*} collectionId Id of the collection to be edited
 * @param {*} resource Resource to be removed from the collection
 */
export const removeResourceFromCollection = (token, collectionId, resource = []) => {
  logger.info(`Remove resource from collection ${collectionId}`);
  const { type, id } = resource;
  return WRIAPI.delete(`collection/${collectionId}/resource/${type}/${id}`, { headers: { Authorization: token } })
    .then(response => WRISerializer(response.data))
    .catch(({ response }) => {
      const { status, statusText } = response;
      logger.error(
        `Error removing resource from collection ${collectionId}: ${status}: ${statusText}`
      );
      throw new Error(
        `Error removing resource from collection ${collectionId}: ${status}: ${statusText}`
      );
    });
};

export default {
  fetchAllCollections,
  fetchCollection,
  createCollection,
  deleteCollection,
  updateCollection,
  addResourceToCollection,
  removeResourceFromCollection
};
<|endoftext|>


<commit_before>s.Game = new Class({
	extend: s.EventEmitter,

	construct: function(options) {
		var self = this;

		this.doRender = false;
		this.lastRender = 0;

		// Store functions that should be called before render
		this.hookedFuncs = [];

		// Bind render function permenantly
		this.render = this.render.bind(this);

		// Configure Physijs
		Physijs.scripts.worker = 'lib/physijs_worker.js';
		Physijs.scripts.ammo = 'ammo.js';

		// Create renderer
		this.renderer = new THREE.WebGLRenderer({
			antialias: true // to get smoother output
		});

		// Set sky color
		this.renderer.setClearColor(0x87CCEB);

		// Create a camera
		this.camera = new THREE.PerspectiveCamera(35, 1, 1, 300000);

		// Configure shadows
		this.renderer.shadowMapEnabled = true;
		this.renderer.shadowMapSoft = true;
		this.renderer.shadowMapCullFrontFaces = false;

		// Create the scene
		this.scene = scene = new Physijs.Scene();

		// If we want to attach the camera to an object, doing this first causes a Physijs error
		// this.scene.add(this.camera);

		// Add the renderer's canvas to the DOM
		this.el = this.renderer.domElement;
		$(document.body).append(this.el);

		// TODO: abstract key listening
		$(document).on('keydown', function(evt) {
			if (evt.which === 13)
				self.toggleFullScreen();
		});

		// Handle window resizes
		$(window).on('resize', this.fitWindow.bind(this));
		this.fitWindow();

		// Handle fullscreen state changes
		$(document).on('fullscreenchange mozfullscreenchange webkitfullscreenchange', this.handleFullscreenChange.bind(this));
		this.handleFullscreenChange();

		// Handle pointer lock changes
		$(document).on('pointerlockchange mozpointerlockchange webkitpointerlockchange', this.handlePointerLockChange.bind(this));
		$(document).on('pointerlockerror mozpointerlockerror webkitpointerlockerror', this.handlePointerLockError.bind(this));

		// Monitor rendering stats
		this.render_stats = new Stats();
		$(this.render_stats.domElement).css({
			position: 'absolute',
			top: 0,
			zIndex: 100
		}).appendTo(document.body);

		this.physics_stats = physics_stats = new Stats();
		$(this.physics_stats.domElement).css({
			position: 'absolute',
			top: '50px',
			zIndex: 100
		}).appendTo(document.body);

		// Physics engine statistics
		this.scene.addEventListener(
			'update',
			function() {
				physics_stats.update();
			}
		);

		// Physics engine ready state
		// TODO: This event seems to fire before the engine is actually doing anything
		this.physicsStarted = false;
		this.scene.addEventListener(
			'ready',
			function() {
				self.physicsStarted = true;
				self.tryInitialize();
			}
		);

		// Start loading models
		// TODO: Load different conditionally based on game type
		s.util.loadModels({
			models: this.models,
			complete: function(models) {
				self.modelsLoaded = true;

				// Store loaded models
				s.models = models;

				// Attempt to start the game
				self.tryInitialize(this);
			}
		});
	},

	// Start the game
	// This method should be overridden
	initialize: function() {
		console.log('Game ready.');

		this.start();
	},

	// Attempt to start the game (if models and physics have begun)
	tryInitialize: function() {
		if (this.modelsLoaded && this.physicsStarted && !this.initialized) {
			this.initialize();
		}
	},

	isFullScreen: function() {
		return (screen.width === window.outerWidth && screen.height === window.outerHeight);
	},

	handleFullscreenChange: function(evt) {
		if (this.isFullScreen()) {
			console.log('Full screen mode entered!');

			this.el.requestPointerLock = this.el.requestPointerLock ||
                                         this.el.mozRequestPointerLock ||
                                         this.el.webkitRequestPointerLock;
			this.el.requestPointerLock();
		}
		else {
			console.log('Full screen mode exited!');
		}
	},

	toggleFullScreen: function() {
		if (!this.isFullScreen()) {
			if (document.documentElement.requestFullScreen) {
				document.documentElement.requestFullScreen();
			}
			else if (document.documentElement.mozRequestFullScreen) {
				document.documentElement.mozRequestFullScreen();
			}
			else if (document.documentElement.webkitRequestFullScreen) {
				document.documentElement.webkitRequestFullScreen(Element.ALLOW_KEYBOARD_INPUT);
			}
		}
		else {
			if (document.cancelFullScreen) {
				document.cancelFullScreen();
			}
			else if (document.mozCancelFullScreen) {
				document.mozCancelFullScreen();
			}
			else if (document.webkitCancelFullScreen) {
				document.webkitCancelFullScreen();
			}
		}
	},

	handlePointerLockChange: function() {
		if (document.mozPointerLockElement === this.el || document.webkitPointerLockElement === this.el) {
			console.log('Pointer Lock was successful.');
			this.pointerLocked = true;
		}
		else {
			console.log('Pointer Lock was lost.');
			this.pointerLocked = false;
		}
	},

	handlePointerLockError: function() {
		console.log('Error while locking pointer.');
		this.pointerLocked = false;
	},

	// Size the renderer to fit the window
	fitWindow: function() {
		this.setSize(window.innerWidth, window.innerHeight);
	},

	// Set the size of the renderer
	setSize: function(width, height) {
		this.width = width;
		this.height = height;
		this.renderer.setSize(width, height);
		if (this.camera) {
			this.camera.aspect = width/height;
			this.camera.updateProjectionMatrix();
		}
	},

	// Add a callback to the rendering loop
	hook: function(callback) {
		this.hookedFuncs.push(callback);
	},

	// Remove a callback from the rendering loop
	unhook: function(callback) {
		var index = this.hookedFuncs.indexOf(callback);
		if (~index)
			this.hookedFuncs.splice(index, 1);
	},

	// Start rendering
	start: function() {
		this.doRender = true;
		requestAnimationFrame(this.render);
	},

	// Stop rendering
	stop: function() {
		this.doRender = false;
	},

	// Perform render
	render: function(now) {
		if (this.doRender) {
			// Simulate physics
			this.scene.simulate();

			// Calculate the time since the last frame was rendered
			var delta = now - this.lastRender;
			this.lastRender = now;
			// Run each hooked function before rendering
			// This may need to happen BEFORE physics simulation
			this.hookedFuncs.forEach(function(func) {
				func(now, delta);
			});

            //////////////////////////
            // RADAR RENDER SEGMENT //
            //////////////////////////

            // Radar sphere rotation with respect to player's current rotation
            this.radarScene.children[3].rotation = s.game.player.root.rotation;

            // Clone of the current player's position
            var selfPosition = s.game.player.root.position.clone();

            // Apply negative scaling to position to compensate for moon size
            selfPosition.addScalar(-250);

            // Apply log scaling to better distribute position
//            selfPosition.x = Math.log(selfPosition.x);
//            selfPosition.y = Math.log(selfPosition.y);
//            selfPosition.z = Math.log(selfPosition.z);

            // Apply position clamping to prevent exceeding visible radar range
            selfPosition.clamp(0,this.radius);

            // Apply normalization and multiplier to cover full sphere coordinates and set the position
            this.radarScene.getChildByName( 'self' ).position = selfPosition.normalize().multiplyScalar(this.radius);

            // moon radar positioning
            var moonPosition = s.game.scene.getChildByName( 'moon').position.clone();
            this.radarScene.getChildByName( 'moon' ).position = moonPosition.normalize().multiplyScalar(this.radius);

            // radar render loop
            this.radarRenderer.render( this.radarScene, this.radarCamera );

            // END RADAR //

			// Render main scene
			this.renderer.render( this.scene, this.camera );

            this.render_stats.update();

			// Request the next frame to be rendered
			requestAnimationFrame(this.render);
		}
	}
});
<commit_msg>minor tweaks to player position on radar<commit_after>s.Game = new Class({
	extend: s.EventEmitter,

	construct: function(options) {
		var self = this;

		this.doRender = false;
		this.lastRender = 0;

		// Store functions that should be called before render
		this.hookedFuncs = [];

		// Bind render function permenantly
		this.render = this.render.bind(this);

		// Configure Physijs
		Physijs.scripts.worker = 'lib/physijs_worker.js';
		Physijs.scripts.ammo = 'ammo.js';

		// Create renderer
		this.renderer = new THREE.WebGLRenderer({
			antialias: true // to get smoother output
		});

		// Set sky color
		this.renderer.setClearColor(0x87CCEB);

		// Create a camera
		this.camera = new THREE.PerspectiveCamera(35, 1, 1, 300000);

		// Configure shadows
		this.renderer.shadowMapEnabled = true;
		this.renderer.shadowMapSoft = true;
		this.renderer.shadowMapCullFrontFaces = false;

		// Create the scene
		this.scene = scene = new Physijs.Scene();

		// If we want to attach the camera to an object, doing this first causes a Physijs error
		// this.scene.add(this.camera);

		// Add the renderer's canvas to the DOM
		this.el = this.renderer.domElement;
		$(document.body).append(this.el);

		// TODO: abstract key listening
		$(document).on('keydown', function(evt) {
			if (evt.which === 13)
				self.toggleFullScreen();
		});

		// Handle window resizes
		$(window).on('resize', this.fitWindow.bind(this));
		this.fitWindow();

		// Handle fullscreen state changes
		$(document).on('fullscreenchange mozfullscreenchange webkitfullscreenchange', this.handleFullscreenChange.bind(this));
		this.handleFullscreenChange();

		// Handle pointer lock changes
		$(document).on('pointerlockchange mozpointerlockchange webkitpointerlockchange', this.handlePointerLockChange.bind(this));
		$(document).on('pointerlockerror mozpointerlockerror webkitpointerlockerror', this.handlePointerLockError.bind(this));

		// Monitor rendering stats
		this.render_stats = new Stats();
		$(this.render_stats.domElement).css({
			position: 'absolute',
			top: 0,
			zIndex: 100
		}).appendTo(document.body);

		this.physics_stats = physics_stats = new Stats();
		$(this.physics_stats.domElement).css({
			position: 'absolute',
			top: '50px',
			zIndex: 100
		}).appendTo(document.body);

		// Physics engine statistics
		this.scene.addEventListener(
			'update',
			function() {
				physics_stats.update();
			}
		);

		// Physics engine ready state
		// TODO: This event seems to fire before the engine is actually doing anything
		this.physicsStarted = false;
		this.scene.addEventListener(
			'ready',
			function() {
				self.physicsStarted = true;
				self.tryInitialize();
			}
		);

		// Start loading models
		// TODO: Load different conditionally based on game type
		s.util.loadModels({
			models: this.models,
			complete: function(models) {
				self.modelsLoaded = true;

				// Store loaded models
				s.models = models;

				// Attempt to start the game
				self.tryInitialize(this);
			}
		});
	},

	// Start the game
	// This method should be overridden
	initialize: function() {
		console.log('Game ready.');

		this.start();
	},

	// Attempt to start the game (if models and physics have begun)
	tryInitialize: function() {
		if (this.modelsLoaded && this.physicsStarted && !this.initialized) {
			this.initialize();
		}
	},

	isFullScreen: function() {
		return (screen.width === window.outerWidth && screen.height === window.outerHeight);
	},

	handleFullscreenChange: function(evt) {
		if (this.isFullScreen()) {
			console.log('Full screen mode entered!');

			this.el.requestPointerLock = this.el.requestPointerLock ||
                                         this.el.mozRequestPointerLock ||
                                         this.el.webkitRequestPointerLock;
			this.el.requestPointerLock();
		}
		else {
			console.log('Full screen mode exited!');
		}
	},

	toggleFullScreen: function() {
		if (!this.isFullScreen()) {
			if (document.documentElement.requestFullScreen) {
				document.documentElement.requestFullScreen();
			}
			else if (document.documentElement.mozRequestFullScreen) {
				document.documentElement.mozRequestFullScreen();
			}
			else if (document.documentElement.webkitRequestFullScreen) {
				document.documentElement.webkitRequestFullScreen(Element.ALLOW_KEYBOARD_INPUT);
			}
		}
		else {
			if (document.cancelFullScreen) {
				document.cancelFullScreen();
			}
			else if (document.mozCancelFullScreen) {
				document.mozCancelFullScreen();
			}
			else if (document.webkitCancelFullScreen) {
				document.webkitCancelFullScreen();
			}
		}
	},

	handlePointerLockChange: function() {
		if (document.mozPointerLockElement === this.el || document.webkitPointerLockElement === this.el) {
			console.log('Pointer Lock was successful.');
			this.pointerLocked = true;
		}
		else {
			console.log('Pointer Lock was lost.');
			this.pointerLocked = false;
		}
	},

	handlePointerLockError: function() {
		console.log('Error while locking pointer.');
		this.pointerLocked = false;
	},

	// Size the renderer to fit the window
	fitWindow: function() {
		this.setSize(window.innerWidth, window.innerHeight);
	},

	// Set the size of the renderer
	setSize: function(width, height) {
		this.width = width;
		this.height = height;
		this.renderer.setSize(width, height);
		if (this.camera) {
			this.camera.aspect = width/height;
			this.camera.updateProjectionMatrix();
		}
	},

	// Add a callback to the rendering loop
	hook: function(callback) {
		this.hookedFuncs.push(callback);
	},

	// Remove a callback from the rendering loop
	unhook: function(callback) {
		var index = this.hookedFuncs.indexOf(callback);
		if (~index)
			this.hookedFuncs.splice(index, 1);
	},

	// Start rendering
	start: function() {
		this.doRender = true;
		requestAnimationFrame(this.render);
	},

	// Stop rendering
	stop: function() {
		this.doRender = false;
	},

	// Perform render
	render: function(now) {
		if (this.doRender) {
			// Simulate physics
			this.scene.simulate();

			// Calculate the time since the last frame was rendered
			var delta = now - this.lastRender;
			this.lastRender = now;
			// Run each hooked function before rendering
			// This may need to happen BEFORE physics simulation
			this.hookedFuncs.forEach(function(func) {
				func(now, delta);
			});

            //////////////////////////
            // RADAR RENDER SEGMENT //
            //////////////////////////

            // Radar sphere rotation with respect to player's current rotation
            this.radarScene.children[3].rotation = s.game.player.root.rotation;

            // Clone of the current player's position
            var selfPosition = s.game.player.root.position.clone();

            // Apply negative scaling to position to compensate for moon size
            selfPosition.addScalar(-500);

//            // Apply log scaling to better distribute position
//            selfPosition.x = Math.log(selfPosition.x) * Math.log(selfPosition.x);
//            selfPosition.y = Math.log(selfPosition.y) * Math.log(selfPosition.y);
//            selfPosition.z = Math.log(selfPosition.z) * Math.log(selfPosition.z);

            // Apply position clamping to prevent exceeding visible radar range
            selfPosition.clamp(0,this.radius);

            // Apply normalization and multiplier to cover full sphere coordinates and set the position
            this.radarScene.getChildByName( 'self' ).position = selfPosition.normalize().multiplyScalar(this.radius);

            // moon radar positioning
            var moonPosition = s.game.scene.getChildByName( 'moon').position.clone();
            this.radarScene.getChildByName( 'moon' ).position = moonPosition.normalize().multiplyScalar(this.radius);

            // radar render loop
            this.radarRenderer.render( this.radarScene, this.radarCamera );

            // END RADAR //

			// Render main scene
			this.renderer.render( this.scene, this.camera );

            this.render_stats.update();

			// Request the next frame to be rendered
			requestAnimationFrame(this.render);
		}
	}
});
<|endoftext|>


<commit_before>var FacilPad = {
	SERVER : "http://localhost:40829",
	COLOURS : [ "ffffff", "ffccc9", "ffce93", "fffc9e", "ffffc7", "9aff99", "96fffb", "cdffff", "cbcefb", "cfcfcf", "fd6864",
		"fe996b", "fffe65", "fcff2f", "67fd9a", "38fff8", "68fdff", "9698ed", "c0c0c0", "fe0000", "f8a102", "ffcc67", "f8ff00", "34ff34",
		"68cbd0", "34cdf9", "6665cd", "9b9b9b", "cb0000", "f56b00", "ffcb2f", "ffc702", "32cb00", "00d2cb", "3166ff", "6434fc", "656565",
		"9a0000", "ce6301", "cd9934", "999903", "009901", "329a9d", "3531ff", "6200c9", "343434", "680100", "963400", "986536", "646809",
		"036400", "34696d", "00009b", "303498", "000000", "330001", "643403", "663234", "343300", "013300", "003532", "010066", "340096" ],
	map : null,
	socket : null,
	layerMarkers : null,
	markersById : { },
	linesById : { },
	mapEvents : null /* Event types: clickMarker, clickLine, click, move, moveEnd, mouseMove */
};

(function(fp) {

	var $;

	if(Function.prototype.bind == null) {
		Function.prototype.bind = function(context) {
			var args = Array.prototype.slice.call(arguments, 1);
			var func = this;

			return function() {
				var newArgs = args.concat(Array.prototype.slice.call(arguments));
				return func.apply(context, newArgs);
			}
		};
	}

	loadJavaScript("lib/async-0.6.2.min.js", function() {
		async.auto({
			"FacilMap" : loadJavaScript.bind(null, "https://api.facilmap.org/facilmap_ol_src.js"),
			"angular" : loadJavaScript.bind(null, "lib/angular-1.2.16.min.js"),
			"socketIo" : loadJavaScript.bind(null, fp.SERVER+"/socket.io/socket.io.js"),
			"marked" : loadJavaScript.bind(null, "lib/marked-0.3.2.min.js"),
			"jqSpinner" : [ "jQuery", loadJavaScript.bind(null, "lib/jquery.ui.spinner-1.10.4.min.js") ],

			"jQuery" : [ "FacilMap", function(next) {
				jQuery = $ = FacilMap.$;
				next();
			}],
			"ready" : [ "jQuery", function(next) {
				$(document).ready(function() { next(); })
			}],

			"loadMap" : [ "FacilMap", "ready", "jQuery", loadMap ],
			"ng" : [ "angular", "jQuery", "socketIo", "loadMap", "marked", "jqSpinner", loadJavaScript.bind(null, "js/ng.js") ]
		});
	});

	function loadMap(callback) {
		var fm = FacilMap;
		var ol = OpenLayers;

		fp.mapEvents = $("<span/>");

		$("button,input[type=submit],input[type=button],input[type=reset]").button();

		fp.map = new FacilMap.Map("map");

		// Deal with z-indexes: Popups should be below map controls
		$("#view-marker-popup,#view-line-popup").appendTo(fp.map.viewPortDiv);

		fp.map.addLayer(new fm.Layer.OSM.Mapnik(ol.i18n("Mapnik"), { permalinkName : "Mpnk" }));
		fp.map.addLayer(new fm.Layer.OSM.MapSurfer.Road(ol.i18n("MapSurfer Road"), { permalinkName : "MSfR" }));
		fp.map.addLayer(new fm.Layer.OSM.CycleMap(ol.i18n("OpenCycleMap"), { permalinkName : "OCyc" }));
		fp.map.addLayer(new fm.Layer.OSM.HikeAndBike(ol.i18n("Hike & Bike Map"), { permalinkName : "HiBi" }));
		fp.map.addLayer(new fm.Layer.OSM.OpenPTMap(ol.i18n("Public transportation"), { permalinkName : "OPTM", visibility : false }));
		fp.map.addLayer(new fm.Layer.other.Relief(ol.i18n("Relief"), { visibility: false, permalinkName : "Rlie" }));

		fp.layerLines = new OpenLayers.Layer.Vector("Lines", { displayInLayerSwitcher: false, visibility: true });
		fp.map.addLayer(fp.layerLines);

		fp.featureHandler = new OpenLayers.Handler.Feature(null, fp.layerLines, {
			"over" : function() {
				$(fp.map.div).addClass("fp-overFeature");
			},
			"out" : function() {
				$(fp.map.div).removeClass("fp-overFeature");
			},
			"click" : function(obj) {
				obj.fpOnClick(fp.xyToPos(fp.featureHandler.fpXy));
			}
		}, { map: fp.map });
		var handleBkp = fp.featureHandler.handle;
		fp.featureHandler.handle = function(e) {
			if(e.type == "click")
				this.fpXy = new OpenLayers.Pixel(e.clientX, e.clientY);

			return handleBkp.apply(this, arguments);
		};
		fp.featureHandler.activate();

		fp.map.events.register("click", map, function(e) {
			fp.mapEvents.trigger("click", [ fp.xyToPos(e.xy) ]);
		});

		fp.map.events.register("move", this, function() {
			setTimeout(function() { fp.mapEvents.trigger("move"); }, 0);
		});

		fp.map.events.register("moveend", this, function() {
			var x = fp.map.getExtent().clone().transform(fp.map.getProjectionObject(), _p());
			setTimeout(function() {
				fp.mapEvents.trigger("moveEnd", [ { top: x.top, left: x.left, bottom: x.bottom, right: x.right, zoom: fp.map.getZoom() } ]);
			}, 0);
		});

		fp.map.events.register("mousemove", this, function(e) {
			fp.mapEvents.trigger("mouseMove", [ fp.xyToPos(e.xy) ]);
		});

		callback();
	}

	// From http://stackoverflow.com/a/4845802/242365
	function loadJavaScript(url, callback) {
		var head = document.getElementsByTagName("head")[0] || document.documentElement;
		var script = document.createElement("script");
		script.src = url;

		// Handle Script loading
	    var done = false;

		// Attach handlers for all browsers
		script.onload = script.onreadystatechange = function() {
		    if(!done && (!this.readyState || this.readyState === "loaded" || this.readyState === "complete") ) {
		        done = true;
		        callback();

		        // Handle memory leak in IE
		        script.onload = script.onreadystatechange = null;
		        if(head && script.parentNode) {
		            head.removeChild(script);
		        }
		    }
		};

		// Use insertBefore instead of appendChild  to circumvent an IE6 bug.
		// This arises when a base node is used (#2709 and #4378).
		head.insertBefore(script, head.firstChild);
	}

	function _p() {
		return new OpenLayers.Projection("EPSG:4326");
	}

	fp.getCurrentView = function() {
		var ret = {
			view: fp.map.getExtent().clone().transform(fp.map.getProjectionObject(), _p()),
			baseLayer: fp.map.baseLayer.permalinkName,
			layers: [ ]
		};
		for(var i=0; i<fp.map.layers.length; i++) {
			if(!fp.map.layers[i].isBaseLayer && fp.map.layers[i].displayInLayerSwitcher && fp.map.layers[i].visibility)
				ret.layers.push(fp.map.layers[i].permalinkName || fp.map.layers[i].name);
		}
		return ret;
	};

	fp.displayView = function(view) {
		if(view == null) {
			fp.map.zoomToMaxExtent();
		} else {
			var bbox = OpenLayers.Bounds.prototype.clone.apply(view.view).transform(_p(), fp.map.getProjectionObject());
			fp.map.zoomToExtent(bbox);

			var matching_layers = fp.map.getLayersBy("permalinkName", view.baseLayer);
			if(matching_layers.length == 0)
				matching_layers = fp.map.getLayersBy("name", view.baseLayer);
			if(matching_layers.length > 0)
				fp.map.setBaseLayer(matching_layers[0]);

			for(var i=0; i<fp.map.layers.length; i++) {
				if(!fp.map.layers[i].isBaseLayer && fp.map.layers[i].displayInLayerSwitcher)
					fp.map.layers[i].setVisibility(view.layers.indexOf(fp.map.layers[i].permalinkName) != -1 || view.layers.indexOf(fp.map.layers[i].name) != -1);
			}
		}
	};

	fp.addMarker = function(marker) {
		fp.deleteMarker(marker);

		var style = {
			externalGraphic: "img/marker-"+marker.style+".png",
			graphicWidth: 21,
			graphicHeight: 25,
			graphicXOffset: -9,
			graphicYOffset: -25
		};
		var feature = new OpenLayers.Feature.Vector(new OpenLayers.Geometry.Point(marker.position.lon, marker.position.lat).transform(_p(), fp.map.getProjectionObject()), null, style);
		feature.fpOnClick = function() {
			fp.mapEvents.trigger("clickMarker", [ marker ]);
		};
		fp.layerLines.addFeatures([ feature ]);
		fp.markersById[marker.id] = feature;
	};

	fp.deleteMarker = function(marker) {
		var markerObj = fp.markersById[marker.id];
		if(!markerObj)
			return;

		delete fp.markersById[marker.id];
		fp.layerLines.removeFeatures([ markerObj ]);
	};

	fp.addLine = function(line) {
		fp.deleteLine(line);

		if(!line.actualPoints || line.actualPoints.length < 2)
			return;

		var points = [ ];
		for(var i=0; i<line.actualPoints.length; i++) {
			if(line.actualPoints[i] != null)
				points.push(new OpenLayers.Geometry.Point(line.actualPoints[i].lon, line.actualPoints[i].lat));
		}

		if(points.length < 2)
			return;

		var style = {
			strokeColor : '#'+line.colour,
			strokeWidth : line.width,
			strokeOpacity : 0.7
		};

		var feature = new OpenLayers.Feature.Vector(new OpenLayers.Geometry.LineString(points).transform(_p(), fp.map.getProjectionObject()), null, style);
		feature.fpOnClick = function(clickPos) {
			fp.mapEvents.trigger("clickLine", [ line, clickPos ]);
		};
		fp.layerLines.addFeatures([ feature ]);
		fp.linesById[line.id] = feature;
	};

	fp.deleteLine = function(line) {
		var lineObj = fp.linesById[line.id];
		if(!lineObj)
			return;

		delete fp.linesById[line.id];
		fp.layerLines.removeFeatures([lineObj]);
	};

	fp.addClickListener = function(listener) {
		fp.featureHandler.deactivate(); // Disable clicking on markers and lines
		$(fp.map.div).addClass("fp-clickHandler");

		var ret = {
			cancel: function() {
				fp.mapEvents.off("click", handler);
				$(fp.map.div).removeClass("fp-clickHandler");
				fp.featureHandler.activate();
			}
		};

		function handler(e, pos) {
			ret.cancel();
			listener(pos);
		}

		fp.mapEvents.on("click", handler);

		return ret;
	};

	fp.xyToPos = function(xy) {
		return fp.map.getLonLatFromViewPortPx(xy).clone().transform(fp.map.getProjectionObject(), _p());
	};

	fp.posToXy = function(pos) {
		var lonlat = new OpenLayers.LonLat(pos.lon, pos.lat).transform(_p(), fp.map.getProjectionObject());
		return fp.map.getViewPortPxFromLonLat(lonlat);
	};

	fp.getLayerInfo = function() {
		var ret = [ ];
		fp.map.layers.forEach(function(it) {
			if(!it.displayInLayerSwitcher)
				return;
			ret.push({ isBaseLayer: it.isBaseLayer, visibility: it.getVisibility(), name: it.name, permalinkName: it.permalinkName });
		});
		return ret;
	};

	fp.showLayer = function(permalinkName, show) {
		var layers = fp.map.getLayersBy("permalinkName", permalinkName);
		if(layers.length == 0)
			return;

		if(layers[0].isBaseLayer && show)
			fp.map.setBaseLayer(layers[0]);
		else
			layers[0].setVisibility(show);
	};

	fp.padId = location.pathname.match(/[^\/]*$/)[0];

})(FacilPad);<commit_msg>Source code cleanup in pad.js<commit_after>var FacilPad = {
	SERVER : "http://localhost:40829",
	COLOURS : [ "ffffff", "ffccc9", "ffce93", "fffc9e", "ffffc7", "9aff99", "96fffb", "cdffff", "cbcefb", "cfcfcf", "fd6864",
		"fe996b", "fffe65", "fcff2f", "67fd9a", "38fff8", "68fdff", "9698ed", "c0c0c0", "fe0000", "f8a102", "ffcc67", "f8ff00", "34ff34",
		"68cbd0", "34cdf9", "6665cd", "9b9b9b", "cb0000", "f56b00", "ffcb2f", "ffc702", "32cb00", "00d2cb", "3166ff", "6434fc", "656565",
		"9a0000", "ce6301", "cd9934", "999903", "009901", "329a9d", "3531ff", "6200c9", "343434", "680100", "963400", "986536", "646809",
		"036400", "34696d", "00009b", "303498", "000000", "330001", "643403", "663234", "343300", "013300", "003532", "010066", "340096" ],
	map : null,
	socket : null,
	markersById : { },
	linesById : { },
	mapEvents : null /* Event types: clickMarker, clickLine, click, move, moveEnd, mouseMove */
};

(function(fp) {

	var $;

	if(Function.prototype.bind == null) {
		Function.prototype.bind = function(context) {
			var args = Array.prototype.slice.call(arguments, 1);
			var func = this;

			return function() {
				var newArgs = args.concat(Array.prototype.slice.call(arguments));
				return func.apply(context, newArgs);
			}
		};
	}

	loadJavaScript("lib/async-0.6.2.min.js", function() {
		async.auto({
			"FacilMap" : loadJavaScript.bind(null, "https://api.facilmap.org/facilmap_ol_src.js"),
			"angular" : loadJavaScript.bind(null, "lib/angular-1.2.16.min.js"),
			"socketIo" : loadJavaScript.bind(null, fp.SERVER+"/socket.io/socket.io.js"),
			"marked" : loadJavaScript.bind(null, "lib/marked-0.3.2.min.js"),
			"jqSpinner" : [ "jQuery", loadJavaScript.bind(null, "lib/jquery.ui.spinner-1.10.4.min.js") ],

			"jQuery" : [ "FacilMap", function(next) {
				jQuery = $ = FacilMap.$;
				next();
			}],
			"ready" : [ "jQuery", function(next) {
				$(document).ready(function() { next(); })
			}],

			"loadMap" : [ "FacilMap", "ready", "jQuery", loadMap ],
			"ng" : [ "angular", "jQuery", "socketIo", "loadMap", "marked", "jqSpinner", loadJavaScript.bind(null, "js/ng.js") ]
		});
	});

	function loadMap(callback) {
		var fm = FacilMap;
		var ol = OpenLayers;

		fp.mapEvents = $("<span/>");

		$("button,input[type=submit],input[type=button],input[type=reset]").button();

		fp.map = new FacilMap.Map("map");

		// Deal with z-indexes: Popups should be below map controls
		$("#view-marker-popup,#view-line-popup").appendTo(fp.map.viewPortDiv);

		fp.map.addLayer(new fm.Layer.OSM.Mapnik(ol.i18n("Mapnik"), { permalinkName : "Mpnk" }));
		fp.map.addLayer(new fm.Layer.OSM.MapSurfer.Road(ol.i18n("MapSurfer Road"), { permalinkName : "MSfR" }));
		fp.map.addLayer(new fm.Layer.OSM.CycleMap(ol.i18n("OpenCycleMap"), { permalinkName : "OCyc" }));
		fp.map.addLayer(new fm.Layer.OSM.HikeAndBike(ol.i18n("Hike & Bike Map"), { permalinkName : "HiBi" }));
		fp.map.addLayer(new fm.Layer.OSM.OpenPTMap(ol.i18n("Public transportation"), { permalinkName : "OPTM", visibility : false }));
		fp.map.addLayer(new fm.Layer.other.Relief(ol.i18n("Relief"), { visibility: false, permalinkName : "Rlie" }));

		fp.layerLines = new OpenLayers.Layer.Vector("Lines", { displayInLayerSwitcher: false, visibility: true });
		fp.map.addLayer(fp.layerLines);

		fp.featureHandler = new OpenLayers.Handler.Feature(null, fp.layerLines, {
			"over" : function() {
				$(fp.map.div).addClass("fp-overFeature");
			},
			"out" : function() {
				$(fp.map.div).removeClass("fp-overFeature");
			},
			"click" : function(obj) {
				obj.fpOnClick(fp.xyToPos(fp.featureHandler.up));
			}
		}, { map: fp.map });
		fp.featureHandler.activate();

		fp.map.events.register("click", map, function(e) {
			fp.mapEvents.trigger("click", [ fp.xyToPos(e.xy) ]);
		});

		fp.map.events.register("move", this, function() {
			setTimeout(function() { fp.mapEvents.trigger("move"); }, 0);
		});

		fp.map.events.register("moveend", this, function() {
			var x = fp.map.getExtent().clone().transform(fp.map.getProjectionObject(), _p());
			setTimeout(function() {
				fp.mapEvents.trigger("moveEnd", [ { top: x.top, left: x.left, bottom: x.bottom, right: x.right, zoom: fp.map.getZoom() } ]);
			}, 0);
		});

		fp.map.events.register("mousemove", this, function(e) {
			fp.mapEvents.trigger("mouseMove", [ fp.xyToPos(e.xy) ]);
		});

		callback();
	}

	// From http://stackoverflow.com/a/4845802/242365
	function loadJavaScript(url, callback) {
		var head = document.getElementsByTagName("head")[0] || document.documentElement;
		var script = document.createElement("script");
		script.src = url;

		// Handle Script loading
	    var done = false;

		// Attach handlers for all browsers
		script.onload = script.onreadystatechange = function() {
		    if(!done && (!this.readyState || this.readyState === "loaded" || this.readyState === "complete") ) {
		        done = true;
		        callback();

		        // Handle memory leak in IE
		        script.onload = script.onreadystatechange = null;
		        if(head && script.parentNode) {
		            head.removeChild(script);
		        }
		    }
		};

		// Use insertBefore instead of appendChild  to circumvent an IE6 bug.
		// This arises when a base node is used (#2709 and #4378).
		head.insertBefore(script, head.firstChild);
	}

	function _p() {
		return new OpenLayers.Projection("EPSG:4326");
	}

	fp.getCurrentView = function() {
		var ret = {
			view: fp.map.getExtent().clone().transform(fp.map.getProjectionObject(), _p()),
			baseLayer: fp.map.baseLayer.permalinkName,
			layers: [ ]
		};
		for(var i=0; i<fp.map.layers.length; i++) {
			if(!fp.map.layers[i].isBaseLayer && fp.map.layers[i].displayInLayerSwitcher && fp.map.layers[i].visibility)
				ret.layers.push(fp.map.layers[i].permalinkName || fp.map.layers[i].name);
		}
		return ret;
	};

	fp.displayView = function(view) {
		if(view == null) {
			fp.map.zoomToMaxExtent();
		} else {
			var bbox = OpenLayers.Bounds.prototype.clone.apply(view.view).transform(_p(), fp.map.getProjectionObject());
			fp.map.zoomToExtent(bbox);

			var matching_layers = fp.map.getLayersBy("permalinkName", view.baseLayer);
			if(matching_layers.length == 0)
				matching_layers = fp.map.getLayersBy("name", view.baseLayer);
			if(matching_layers.length > 0)
				fp.map.setBaseLayer(matching_layers[0]);

			for(var i=0; i<fp.map.layers.length; i++) {
				if(!fp.map.layers[i].isBaseLayer && fp.map.layers[i].displayInLayerSwitcher)
					fp.map.layers[i].setVisibility(view.layers.indexOf(fp.map.layers[i].permalinkName) != -1 || view.layers.indexOf(fp.map.layers[i].name) != -1);
			}
		}
	};

	fp.addMarker = function(marker) {
		fp.deleteMarker(marker);

		var style = {
			externalGraphic: "img/marker-"+marker.style+".png",
			graphicWidth: 21,
			graphicHeight: 25,
			graphicXOffset: -9,
			graphicYOffset: -25
		};
		var feature = new OpenLayers.Feature.Vector(new OpenLayers.Geometry.Point(marker.position.lon, marker.position.lat).transform(_p(), fp.map.getProjectionObject()), null, style);
		feature.fpOnClick = function() {
			fp.mapEvents.trigger("clickMarker", [ marker ]);
		};
		fp.layerLines.addFeatures([ feature ]);
		fp.markersById[marker.id] = feature;
	};

	fp.deleteMarker = function(marker) {
		var markerObj = fp.markersById[marker.id];
		if(!markerObj)
			return;

		delete fp.markersById[marker.id];
		fp.layerLines.removeFeatures([ markerObj ]);
	};

	fp.addLine = function(line) {
		fp.deleteLine(line);

		if(!line.actualPoints || line.actualPoints.length < 2)
			return;

		var points = [ ];
		for(var i=0; i<line.actualPoints.length; i++) {
			if(line.actualPoints[i] != null)
				points.push(new OpenLayers.Geometry.Point(line.actualPoints[i].lon, line.actualPoints[i].lat));
		}

		if(points.length < 2)
			return;

		var style = {
			strokeColor : '#'+line.colour,
			strokeWidth : line.width,
			strokeOpacity : 0.7
		};

		var feature = new OpenLayers.Feature.Vector(new OpenLayers.Geometry.LineString(points).transform(_p(), fp.map.getProjectionObject()), null, style);
		feature.fpOnClick = function(clickPos) {
			fp.mapEvents.trigger("clickLine", [ line, clickPos ]);
		};
		fp.layerLines.addFeatures([ feature ]);
		fp.linesById[line.id] = feature;
	};

	fp.deleteLine = function(line) {
		var lineObj = fp.linesById[line.id];
		if(!lineObj)
			return;

		delete fp.linesById[line.id];
		fp.layerLines.removeFeatures([lineObj]);
	};

	fp.addClickListener = function(listener) {
		fp.featureHandler.deactivate(); // Disable clicking on markers and lines
		$(fp.map.div).addClass("fp-clickHandler");

		var ret = {
			cancel: function() {
				fp.mapEvents.off("click", handler);
				$(fp.map.div).removeClass("fp-clickHandler");
				fp.featureHandler.activate();
			}
		};

		function handler(e, pos) {
			ret.cancel();
			listener(pos);
		}

		fp.mapEvents.on("click", handler);

		return ret;
	};

	fp.xyToPos = function(xy) {
		return fp.map.getLonLatFromViewPortPx(xy).clone().transform(fp.map.getProjectionObject(), _p());
	};

	fp.posToXy = function(pos) {
		var lonlat = new OpenLayers.LonLat(pos.lon, pos.lat).transform(_p(), fp.map.getProjectionObject());
		return fp.map.getViewPortPxFromLonLat(lonlat);
	};

	fp.getLayerInfo = function() {
		var ret = [ ];
		fp.map.layers.forEach(function(it) {
			if(!it.displayInLayerSwitcher)
				return;
			ret.push({ isBaseLayer: it.isBaseLayer, visibility: it.getVisibility(), name: it.name, permalinkName: it.permalinkName });
		});
		return ret;
	};

	fp.showLayer = function(permalinkName, show) {
		var layers = fp.map.getLayersBy("permalinkName", permalinkName);
		if(layers.length == 0)
			return;

		if(layers[0].isBaseLayer && show)
			fp.map.setBaseLayer(layers[0]);
		else
			layers[0].setVisibility(show);
	};

	fp.padId = location.pathname.match(/[^\/]*$/)[0];

})(FacilPad);<|endoftext|>


<commit_before><commit_msg>refactoring<commit_after><|endoftext|>