WME UR-MP tracking

Track UR and MP in the Waze Map Editor

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name        WME UR-MP tracking
// @version     3.9.24
// @description Track UR and MP in the Waze Map Editor
// @namespace   https://greasyfork.org/fr/scripts/368141-wme-ur-mp-tracking
// @include     /^https:\/\/(www|beta)\.waze\.com\/(?!user\/)(.{2,6}\/)?editor\/?.*$/
// @icon        data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAAZiS0dEAAAAAAAA+UO7fwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB94DDwolKCvyQLIAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAGcElEQVRYw82Xf1BU1xXHv/e9t7DsLiy6uwYEZBVYNGi7gwnYNpk6kx9TrcZJGe0v/cOONkPTJuMYJk5NGxUcp9ohOqZDU5wxk+CMQrEZneIv0Pwgmk6LElJKRECJbBaVZdld2F/33Xv6h0JqY/ghGSdn5s67950z53zeOWfuvQ+YhvT399/1/EZIVVXVlOzZZA07OjqwYMGCsfWKFSsKvF7vHCmlQVEU3eFw/PvkyZOfjepramqwdu3ar+erjh49OjZft25dmsvl+lOey3Uj1zV/OCd//kiOK38kNy/v8/z8/LqlS5cWjtpu2rTp68sAACxZsqTE5/O9ZdRU05wkBQ8nq7AlKBTUCe1Bwa6FBcJCxpItlt0bN24sLy0t5bW1tVizZs30AOrq6lhFefnPQpHoG3kWzfzTzEQqmqHBqDIm6bYTnYDWgE6H+2KsLaBzi8n40vPP/2r/9u07yOPxfKVvdTIAfX193/KHRt6Ya1Yf2ppvooctCuOxGOO6hFQ0xONxCB7HbHMCW5yq0fWIVK+GYoU93d0ftLe3exoaGnDo0KGpA1y8eBE9PT0JwyMjv4tFo0+9Ot+MLJPCyGxF2s83Q5s5C+ErbUhd8hTsqzZguONfSJAc6YkKuxjQLcFIPOvmzRs1LpfrK2Mo4wEUFhbC7XY7wrH4skdmGJBlUkgSwTAzDcmLv4+MDa9g9i9+i4zSCsx4/IdQLakAgeVYNMy3aIjz+BO7du3KHi+GMlH6A4FAciQay15k1aAxMIAh2nsZA8ffhIxHYXv6x2Cqhv7D+8EH+kGMIUkBnCaVVAatpaXl2WkBhMNhIiKYVQZltGUZA8VjANGdF/RFS9+ZmlUGBQyBQIBNC8DhcJBB06QnIqHfcW6ckwfHsxuhJCZhsLEOJHSk/eQ3SLClASAQAG9MMJ0ITqezf1oAnZ2dfcYEw4kPBzkicQJJID5wA6GPP0Tfn7fDU12B669vhf/9v4MH/IAEbkUlXRkWAGPe6urqvwEAjWVrCgDd3d0oKCiIWkxJZzxRIc/74oAuER0cxNV9W3Hz1F8hYMBg82n07NmMWCAEziV9MsTZtbCAyWTaxRiL3q4amzpATk4Odu/eLU0m07FEVf24tp9jKKaTlAQyGCFVDboQEIoGSkyCLiXCXODULY6IoE8cdvsRAGhtbb3/EgDA2bNnrzLIPwzEZfjIDc5UIaHr9KUhBeGfQ5xdCukwJxn/smjhwlsA4Ha77x/g4MGDAIBPOz49ojK0vTsk0RYURLqAzr8YggsEozod8AokGbTWWQ5HQ+Vrr9FE/icEWL9+PUZrmO10vhoXMlTrE8wflaRzCc4ldC4R45Kq+gWLEIWtKSl7m5qaeiaT3QkBfD4f9uzZAwA4ferUaavVWnk5LNAUEIwLASEEpBA4MyTxnwjBwNjbFy5cqJnsCTshgM1mQ1lZ2dj6xRdfOJCSktJ5IgR0hwmSS3SFJZpGiEkiWVFR8RZjTIzat7S03N99oL6+HiUlJaivr1cqKyuX+gf9z2mqmkKAFo1G3JIpdpuB4YUUicPDDB2cQcbiItVqfVfXdZ3r+vn02el7z507F7xzoiIzM3NyAI1NjXjyiScBAO5vuwu8Xm9TmnPuQ9YZqSACNIMGHgmTt8/D7BowoBPSMzNJMyYxoQsQEXo7L0NyXr169eqyvfv2BkbLabPZxgc4fvw4Vq5ceXsfmJeTPTAwcMj9ne9+b/3LLyPZaiWAGJiC4cAQDpSXw9N7DelZWVi7+SXMmp0BgMAUhdrOn2dVO3YARLWlvy59btvvtw1N6R5YXFScbU2xXlq18hnyDQ5STBcyyjmNDi4ldXZ2UnFxMZ1pbCQuJd2lF0L+46OPaJ5zXtxus5cT0fj91tvbOzYverTIaZtpa3Y/8ij13BqQfYEAfeb3f2l4gkG6dKWLPIHgPfWfB0N04v0PKCMjU8x1zt1W8qMSAwCsembV3SXo6upCbm4uAGDZD5altrS0HDGazU9v2PoKrA4HhJC411ZOBKiqAinlPT+KCFAU0HvvvMPeO3ZsKDEx8Zfefm8dACxfvhwNDQ1390BxUfGC9vb2PyqKstxsscBosYAkYTrCGCClRNDvh9D1GBGVhYZD+0f12v8aP/b4Y4sXLlrYBWDfeEfo/YEwAGCapjnsdnvWzp07r48pm5ubH/gv3JYtW/6/XvTAgj/IWN98+S9tiGRBMpU45gAAAABJRU5ErkJggg==
// @grant       GM_addElement
// @grant       GM_getValue
// @grant       GM_setValue
// @grant       GM_xmlhttpRequest
// @grant       unsafeWindow
// @copyright   2023, dummyd2, seb-d59, jangliss
// @author      dummyd2, seb-d59, jangliss
// @connect     waze.netdork.net
// ==/UserScript==

/*******
 *
 *  You are free to:
 *   Share, copy, and redistribute the script in any medium or format
 *   under the following terms:
 *   Attribution - You must give appropriate credit. You may do so in any
 *     reasonable manner, but not in any way that suggests the licensor
 *     endorses you or your use.
 *
 *   NonCommercial - You may not use the script for commercial purposes.
 *
 *   NoModifications - You may NOT MODIFY the script.
 *
 *  You are invited to contact the author: jangliss on waze forum for more details.
 *
********/

function downloadHelperInjected () {
  window.downloadHelper = {
    jobs: [],
    _waitForData: function (id) {
      if (this.jobs.length <= id) {
        this.jobs[id].callback({ url: null, data: null, callback: this.jobs[id].callback, status: 'error', error: 'Request not found' })
      } else {
        if (this.jobs[id].status === 'success' || this.jobs[id].status === 'error') {
          this.jobs[id].callback(this.jobs[id])
        } else {
          if (this.jobs[id].status === 'downloading' && this.jobs[id].progressCallback) {
            this.jobs[id].progressCallback(this.jobs[id])
          }
          const _this = this
          window.setTimeout(function () {
            _this._waitForData(id)
          }, 500)
        }
      }
    },
    add: function (url, callback, progressCallback) {
      this.jobs.push({ url, data: null, callback, progressCallback, status: 'added', progression: 0, error: '' })
      const _this = this
      window.setTimeout(function () {
        _this._waitForData(_this.jobs.length - 1)
      }, 500)
    }
  }
}

GM_addElement('script', {
  // eslint-disable-next-line quotes
  textContent: '' + downloadHelperInjected.toString() + " \n" + 'downloadHelperInjected();'
})

if (typeof unsafeWindow === 'undefined') {
  unsafeWindow = (function () {
    const dummyElem = document.createElement('p')
    dummyElem.setAttribute('onclick', 'return window;')
    return dummyElem.onclick()
  }())
}
function lookFordownloadHelperJob () {
  for (let i = 0; i < unsafeWindow.downloadHelper.jobs.length; i++) {
    if (unsafeWindow.downloadHelper.jobs[i].status === 'added') {
      unsafeWindow.downloadHelper.jobs[i].status = cloneInto('downloading', unsafeWindow.downloadHelper.jobs[i])
      // eslint-disable-next-line no-unused-vars
      const f = (function () {
        const job = i
        GM_xmlhttpRequest({
          method: 'GET',
          headers: { 'User-Agent': 'Mozilla/5.0', Accept: 'text/plain' },
          synchronous: false,
          timeout: 10000,
          url: unsafeWindow.downloadHelper.jobs[job].url,
          onerror: function (r) {
            unsafeWindow.downloadHelper.jobs[job].status = cloneInto('error', unsafeWindow.downloadHelper.jobs[job])
          },
          ontimeout: function (r) {
            console.debug('TOTO Timeout while getting area from server: ', r)
            unsafeWindow.downloadHelper.jobs[job].status = cloneInto('error', unsafeWindow.downloadHelper.jobs[job])
          },
          onload: function (r) {
            unsafeWindow.downloadHelper.jobs[job].status = cloneInto('success', unsafeWindow.downloadHelper.jobs[job])
            unsafeWindow.downloadHelper.jobs[job].data = cloneInto(r.responseText, unsafeWindow.downloadHelper.jobs[job])
          },
          onprogress: function (r) {
            unsafeWindow.downloadHelper.jobs[job].progression = cloneInto(r.total === 0 ? 0 : r.loaded / r.total, unsafeWindow.downloadHelper.jobs[job])
          }
        })
      }())
    }
  }
  window.setTimeout(lookFordownloadHelperJob, 2000)
}
window.setTimeout(lookFordownloadHelperJob)
function GMStorageHelperInjected () {
  window.GMStorageHelper = {
    jobs: [],
    _waitForData: function (id) {
      if (this.jobs.length <= id) {
        if (this.jobs[id].callback) {
          this.jobs[id].callback({ entry: null, data: null, callback: this.jobs[id].callback, status: 'error', error: 'Request not found' })
        }
      } else {
        if (this.jobs[id].status === 'done') {
          if (this.jobs[id].callback) {
            this.jobs[id].callback(this.jobs[id])
          }
        } else {
          const _this = this
          window.setTimeout(function () {
            _this._waitForData(id)
          }, 500)
        }
      }
    },
    load: function (entry, callback) {
      this.jobs.push({ task: 'load', entry, data: null, callback, status: 'added', error: '' })
      const _this = this
      const jobId = this.jobs.length - 1
      window.setTimeout(function () {
        _this._waitForData(jobId)
      }, 500)
    },
    save: function (entry, data, callback) {
      this.jobs.push({ task: 'save', entry, data, callback, status: 'added', error: '' })
      const _this = this
      const jobId = this.jobs.length - 1
      window.setTimeout(function () {
        _this._waitForData(jobId)
      }, 500)
    }
  }
}

GM_addElement('script', {
  // eslint-disable-next-line quotes
  textContent: '' + GMStorageHelperInjected.toString() + " \n" + 'GMStorageHelperInjected();'
})

if (typeof unsafeWindow === 'undefined') {
  unsafeWindow = (function () {
    const dummyElem = document.createElement('p')
    dummyElem.setAttribute('onclick', 'return window;')
    return dummyElem.onclick()
  }())
}

function lookForGMStorageHelperJob () {
  for (let i = 0; i < unsafeWindow.GMStorageHelper.jobs.length; i++) {
    if (unsafeWindow.GMStorageHelper.jobs[i].status === 'added') {
      if (unsafeWindow.GMStorageHelper.jobs[i].task === 'load') {
        unsafeWindow.GMStorageHelper.jobs[i].data = cloneInto(GM_getValue(unsafeWindow.GMStorageHelper.jobs[i].entry, null), unsafeWindow.GMStorageHelper.jobs[i])
      }
      if (unsafeWindow.GMStorageHelper.jobs[i].task === 'save') {
        GM_setValue(unsafeWindow.GMStorageHelper.jobs[i].entry, unsafeWindow.GMStorageHelper.jobs[i].data)
        unsafeWindow.GMStorageHelper.jobs[i].data = cloneInto(null, unsafeWindow.GMStorageHelper.jobs[i])
      }
      unsafeWindow.GMStorageHelper.jobs[i].status = cloneInto('done', unsafeWindow.GMStorageHelper.jobs[i])
    }
  }
  window.setTimeout(lookForGMStorageHelperJob, 2000)
}

window.setTimeout(lookForGMStorageHelperJob)

// eslint-disable-next-line camelcase
function WMEURMPT_Injected () {
  // eslint-disable-next-line quotes
  const NL = "\n"
  const WMEURMPT = {}
  WMEURMPT.isDebug = false
  WMEURMPT.urmpt_version = '3.9.24'
  WMEURMPT.URList = []
  WMEURMPT.URMap = {}
  WMEURMPT.MPList = []
  WMEURMPT.MPMap = {}
  WMEURMPT.MCList = []
  WMEURMPT.MCMap = {}
  WMEURMPT.PURList = []
  WMEURMPT.PURMap = {}
  WMEURMPT.stackedURList = []
  WMEURMPT.stackedUR = { id: 0, oriX: 0, oriY: 0 }
  WMEURMPT.dom = {}
  WMEURMPT.driveArea = []
  WMEURMPT.managedAreas = []
  WMEURMPT.sortModeListUR = { ageASC: 1, ageDSC: -1, typeASC: 2, typeDSC: -2, commentCountASC: 3, commentCountDSC: -3, distanceASC: 4, distanceDSC: -4, lastCommentASC: 5, lastCommentDSC: -5 }
  WMEURMPT.sortModeListMP = { priorityASC: 1, priorityDSC: -1, typeASC: 2, typeDSC: -2, distanceASC: 3, distanceDSC: -3 }
  WMEURMPT.sortModeListMC = { distanceASC: 1, distanceDSC: -1, commentCountASC: 2, commentCountDSC: -2, ageASC: 3, ageDSC: -3 }
  WMEURMPT.sortModeListPUR = { ageASC: 1, ageDSC: -1, categoriesASC: 2, categoriesDSC: -2, distanceASC: 3, distanceDSC: -3, nameASC: 4, nameDSC: -4, nbpurASC: 5, nbpurDSC: -5 }
  WMEURMPT.URFilterList = { hideClosed: 1, hideWithoutCommentFromMe: 2, hideWithCommentCount: 4, hideOutOfMyManagedArea: 8, hideVisited: 16, hideBlacklisted: 32, hideWhitelisted: 64, hideGE: 128, hideNotKW: 256, hideLimitTo: 512, hideType: 1024, hideArea: 2048, hideLastCommentFromEditor: 4096, hideTagged: 8192, hideNoNewComment: 16384, hideOutOfMyDriveArea: 32768 }
  WMEURMPT.MPFilterList = { hideClosed: 1, hideOutOfMyManagedArea: 2, hideVisited: 4, hideBlacklisted: 8, hideWhitelisted: 16, hideLimitTo: 32, hideType: 64, hideArea: 128, hideOutOfMyDriveArea: 256 }
  WMEURMPT.MCFilterList = { hideOutOfMyManagedArea: 1, hideVisited: 2, hideBlacklisted: 4, hideWhitelisted: 8, hideLimitTo: 16, hideArea: 32, hideNotKW: 64, hideOutOfMyDriveArea: 128 }
  WMEURMPT.PURFilterList = { hideOutOfMyManagedArea: 1, hideVisited: 2, hideBlacklisted: 4, hideWhitelisted: 8, hideLimitTo: 16, hideArea: 32, hideNotKW: 64, hideCategorie: 128, hideOutOfMyDriveArea: 256 }
  WMEURMPT.taggedURList = ['[NOTE]', '[CONSTRUCTION]', '[ROADWORKS]', '[CLOSURE]', '[EVENT]', '[WSLM]']
  WMEURMPT.URAgeColIsLastComment = false
  WMEURMPT.disableScrolling = false
  WMEURMPT.currentSortModeUR = WMEURMPT.sortModeListUR.ageDSC
  WMEURMPT.currentSortModeMP = WMEURMPT.sortModeListMP.priorityDSC
  WMEURMPT.currentSortModeMC = WMEURMPT.sortModeListMC.distanceASC
  WMEURMPT.currentSortModePUR = WMEURMPT.sortModeListPUR.distanceASC
  WMEURMPT.sortHistoryUR = [WMEURMPT.currentSortModeUR]
  WMEURMPT.sortHistoryMP = [WMEURMPT.currentSortModeMP]
  WMEURMPT.sortHistoryMC = [WMEURMPT.currentSortModeMC]
  WMEURMPT.sortHistoryPUR = [WMEURMPT.currentSortModePUR]
  WMEURMPT.currentURFilter = WMEURMPT.URFilterList.hideClosed + WMEURMPT.URFilterList.hideBlacklisted + WMEURMPT.URFilterList.hideLimitTo
  WMEURMPT.currentMPFilter = WMEURMPT.MPFilterList.hideClosed + WMEURMPT.MPFilterList.hideBlacklisted + WMEURMPT.MPFilterList.hideLimitTo
  WMEURMPT.currentMCFilter = WMEURMPT.MCFilterList.hideBlacklisted + WMEURMPT.MCFilterList.hideLimitTo
  WMEURMPT.currentPURFilter = WMEURMPT.PURFilterList.hideBlacklisted + WMEURMPT.PURFilterList.hideLimitTo
  WMEURMPT.currentURID = null
  WMEURMPT.currentMPID = null
  WMEURMPT.currentMCID = null
  WMEURMPT.currentPURID = null
  WMEURMPT.selectedURID = null
  WMEURMPT.selectedMPID = null
  WMEURMPT.selectedMCID = null
  WMEURMPT.selectedPURID = null
  WMEURMPT.displayLegend = true
  WMEURMPT.isEnabled = true
  WMEURMPT.isComputeDistances = true
  WMEURMPT.isAutoScan = true
  WMEURMPT.isScanningWME = false
  WMEURMPT.currentURKeyWord = ''
  WMEURMPT.currentMCKeyWord = ''
  WMEURMPT.currentPURKeyWord = ''
  WMEURMPT.currentURLimitTo = 100
  WMEURMPT.currentMPLimitTo = 100
  WMEURMPT.currentMCLimitTo = 100
  WMEURMPT.currentPURLimitTo = 100
  WMEURMPT.currentUROnlyType = 6
  WMEURMPT.currentMPOnlyType = 106
  WMEURMPT.currentUROnlyArea = ''
  WMEURMPT.currentMPOnlyArea = ''
  WMEURMPT.currentPUROnlyArea = ''
  WMEURMPT.purInvertFilter = false
  WMEURMPT.urtInvertFilter = false
  WMEURMPT.currentURCommentsCount = 0
  WMEURMPT.wazeServerWaitingTimeToRetry = 1
  WMEURMPT.mapCenterLonLat = null
  WMEURMPT.scanAreaBoundsList = []
  WMEURMPT.scanAreaBoundsCount = 0
  WMEURMPT.scanUR = true
  WMEURMPT.scanMP = true
  WMEURMPT.scanMC = true
  WMEURMPT.scanPUR = true
  WMEURMPT.flashOdd = true
  WMEURMPT.URDescriptionMaxLength = 15
  WMEURMPT.MPDescriptionMaxLength = 20
  WMEURMPT.MCSubjectMaxLength = 9
  WMEURMPT.MCBodyMaxLength = 12
  WMEURMPT.PURCategoriesMaxLength = 9
  WMEURMPT.PURNameMaxLength = 12
  WMEURMPT.visitedURBeforeActionsSaved = []
  WMEURMPT.visitedMPBeforeActionsSaved = []
  WMEURMPT.visitedTPBeforeActionsSaved = []
  WMEURMPT.lastUploadedWKT = null
  WMEURMPT.securityOn_visitedURBeforeActionsSaved_set = false
  WMEURMPT.servers = [{ name: 'jangliss', url: 'https://waze.netdork.net/urmp/' }]
  WMEURMPT.customAreaList = []
  WMEURMPT.areaList = { custom: [], country: [] }
  WMEURMPT.statsCSV = ''
  WMEURMPT.policySafeHTML = null
  WMEURMPT.policySanitizeHTML = null
  WMEURMPT.icon_comments = 'iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAAZiS0dEAAAAAAAA+UO7fwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB94DDg83H1XMMOAAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAEQ0lEQVRYw+2XTUhcVxTHf0+dwcxUHawuxImtH0hbBEebGLCFutGFgSaBriImoXRRBLciqYuKza4bN21dVFcJgouE2IKolIJYP0BmFCwKoyJxksyMTGZ0Zvpax3u6eW+YD40abTftH+7mvnfv/3/OPfecc+G/Du0ca2sBJ5Bv7BMDXgDr/6Tgz4CfgAAQAaIGcQzYB8KAH/gZuHVRpAXAbeAlIIDk5uaKzWZTRUVFUlxcLMXFxVJUVCQ2m03y8vLE/A/wAV8Aljc9gk+AB8BHABUVFTQ0NHDt2jWuXLlCbW0tZWVlKKXw+/14vV4WFxdZWFhgaWlJdnZ2zP0XgF7g17NY/qXhUrHb7aq/v195PB45DZRSsrKyIgMDA2K1Wk1vhAxvnAq3AR2QiooKtba2JkqpNILTIJFIyMbGhqqvr1eGiEOg6yTyauBPQOrq6lQikTgTaaYnRET8fr80NzcLoAzDPn6dgBlA6uvrVTgcfmPyTBHb29tSU1NjHscvgP0o8k8BcTgcanp6+tzkmSJmZ2dNAQcGVxZ+A+TmzZvnZz0GHR0dZjwMAdZU8hLgldVqVUNDQxdmfSZmZmZML2wAhZl3fr+goEBWV1ezXHiUmNMIzLw94XBY7Ha7KaIkJ0XAW0COxWKhqqoqPVtpGpqmMTw8zN27d3ny5Ely/uHDh9y5c4epqSmUUiilePz4Mffu3WNychJN0xCRtH2MYMxKhNeBmMPhkN3d3SxLxsfHpbCwUABxOp3i8Xhkfn4+mXbz8/MlEAiI1+tNzmmaJj6fL22fcDgsNTU1ZhyUpnrgBXB4cHAgq6urAEnlAJubm8TjcQACgQCRSIS1tbXkd13XCYVCbG1tJedEhPX19OKo6zper1cD/jISU1pdeJ6TkyN9fX1ZHvD5fNLa2ipOp1M6OzslGAxKNBqVlpYWKS8vl46ODonH4xKNRqW9vV2cTqfcuHEjKxZGRkZM62ePygXDgDQ1NalgMJi1OBQKidvtlkgkkvy2v78vHo9HYrFYcm5vb0+Wl5dF1/WsQKyurjYF3AdyMgWUmOc3ODiYFv2ZEX/czTjqFpj/9fT0pJbpD49LxQ9MEXNzc+oiMqCIyNjYmFgsFmXUg+9eVwvyzXrQ1NR0IeSPHj0Sh8Nhun4JePukingLEJfLda6sFwwGpaurS9nt9lTyd0/TD1w/j4BQKCS9vb1SWloqmqaZ5z4JlGYS5R1BbgM+B7h8+bLouq6Nj48zOjoqT58+1RKJBC6Xi7a2NmlsbNQqKys5PDzk2bNneDweJiYmcLvd5l7K6Kq+B74GEqex/r7ZvXR3d6urV6+qlCZTjA5YThgxwA18C7x/lnfBV8A3Keo1Y0SM8jkLxI2u6YNj3gW/G2+DdeD5WZrQFoMo05ofgXeOSBoWg/ySMfJf134fh9QYuAT8YVjzEvgBGAFeHbP2wBgXivcAF//jX8TfP8rg1M0AqeYAAAAASUVORK5CYII='
  WMEURMPT.icon_distance = 'iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAAZiS0dEAAAAAAAA+UO7fwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB94DDhYIKkhWRgAAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAACXUlEQVRYw+3Uv2sTYRgH8Cd3Zzyvh8nlEpPGJRSalpOWBpq2QTEx3KExiwgR7FK7OLiJZBD8sejSgnRxFpf+BUWHHjSTLQULdqh0rimUbHfvvffzvcdB/QO61OU++8MDz/d5HoBEIpFIJBKJxP82MTHR1jRtaBjGs3OWcnNzc98bjcYPACico45vNpuvpqamftXr9RtCJpPJrq6ulk9OTnLb29uXdV0XT09P3SAIUpVKRTRN09E0jSuXy1dM07SWlpbEfD6f2trautTtdkvT09PZ3d3dfK/XI8fHx9zh4aGzsLBwleO4cG9vL9B1XQ7D0CeEMEVRJNM0vfn5eUVV1es7OzuyAAAQRRGIomjNzMy8mJycbAHAF57ns+Pj43c0TftUrVYLlNLHpVLpLsdxG4qicADwhjEWh2EYAcA1SZJej42NZQHgviRJZiaTGRSLxa+qqr4PguCb67o/VVV9IsvyS0EQ3CiK/owRAIDjONjf3783HA6fr62tGaPR6KnneY/6/f7t0Wj0luf5XqfTqRUKhQ+O4xi6rjeLxeIGIUSklAq5XO5du91uptPpxXq9/rHVatUkSeoCwPrKykojnU53z87O+svLy7dkWV4/Ojq6yfP8n0BqtdrDwWCAYRi6lmW5iIiO43iUUh8R0bIs6nmeH8cxUkqJ4zghIjLbtkkQBIwxhpZlEURkrutGlFLCGEPf9wPbtgkioud5gW3bLiKibduEMeZvbm7GhmEspqrV6oPZ2dnPlUrFjuM4dRGLLwgCHBwciISQzr+G8t848IKOLwUADACc5A8lEr8BN7wbxzXrd3cAAAAASUVORK5CYII='
  WMEURMPT.icon_age = 'iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAAZiS0dEAAAAAAAA+UO7fwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB94DDhYcMwKTOZUAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAFF0lEQVRYw+2XTWgUZxjHf+/sZnd2EpPsBhWaoB4MVczBbZo05FAPNuApEdSLRAWbguKxtFAoLRLJxQZyaQk9FkR7kKQHQyUXsSlBUGLoITbihlhDNMmucTeZnf2Y9+nB2bJZ893QU/8wMLzzvs/zf77fgf+xM/D9l8qCwKfAL8AMsOw9SeAP4Afg2E4rNYD3gR8BKTzBYFADGpBAIOD6/X4p+j4LdAE1/9Z1EeAL4CegxbKsfFNTU669vT135cqV3JMnT17btq2uXbu21NbWpsLhsHZd143H49VAO9AGvAT+3I7lB4F7xVbfuHHjRSKRyIqIKyISi8WSIyMjtohk5S1yk5OTTjQafVV0Lg1c36oHDgJDwAfhcDjX3t6+UFVV9aK3t7fWsqyAiKCUUqZp2nNzc9m6urqAJ8+oqanxRSKR16lU6vXhw4fzk5OTlcBHwF7gV4/Uhm6/B0g4HHYmJiZSshJaRCSZTM5XVFQkAX3u3LmXRV5YsbenpydR5I1LgNoo4b4FJBKJ5ArKtda6VPLdu3cXTNN0AWlubk47jrOCqH4LERHp7u5e9AgsAUeKlZWiHvgS4MyZM68OHTpUISKilHqHtWEY/5z3+XzvyFNvgYhw+fLlMuANUA70rUfgc8ACmJqacgqCNpm0q8ZWKUU6ndZevwD4pNArjFWazGeWZeX6+vpeDA4OvrdTjaS2trbcdd2KU6dOLXlLX69GoBPg6NGj+sKFC3tDoVBIRGQLetb0lFJKGYZR2dnZqSzL0sDHQFUpgXaAaDSqq6urfVtxv2EYBAKBd/aWGnDixAmjvLxcPLLH/SX7PwwGg9LU1CSAsVbyrYZ4PK6HhoZSpmk6IoJpmm5jY2MwFArtKsgRETFNM3TgwIGl+fn5UHE1FLBsGIZ78eLFOdu2bdkAw8PDiUIZKqW0aZp50zRd0zTdQCDgnjx5Mp5MJtPFZ27duvWXZVnLgAv0G6VdUWtt3L5923r8+LHeyGrLsrRSSnuuVo7j+BzHMRzHMbLZrDExMRGIx+Mrwjw6OmrZth3wQmAWh8AFXJ/Pp7u6utLNzc27NiLQ2tpqnT9/PjE+Pl65SqT02bNnM/v27TOLF/v6+oL3799fGhsbqwQWS3NgWinVUFtbW+7z+YLr5YD3LdTf3+/PZDKZoooSQPl8PvH7/VWAv0ROMJVKlXljPFZK4Ld8Pt/w4MEDA8grpfzrlZUnuCwYDJat2ZlKjJiamsomEgkTyAOPSsvwZ4Dx8XGePn3qbjS1NlMhhT2FchwYGJBUKoXXFX9f7cwsIB0dHbM3b978S3YItm3nrl69GguHw0nPsO/WIt1VGJ1Kqem1JuFWoLXWCwsLucrKyllPdg7Ys9YwGgDGAFpaWkKFpNruDCjkgOu6rlKqwlv+Bphb71yHd42Snp6ehGfFliwuWcpGo9GUZ8woEN4M+etepkp3d/diMpnMTk9PL+ZyufxqyoqVaq214zjZ58+fv5mZmbGLlM94V7NN4/tCPkQikQVg8eHDh9NFigqv6VIv3blzZxZY8LK9oLxjO/8Dl7xrlADS2tqaGBwcXEqn07aIyMjIyOzp06dTz549i4tIPhaLLff29i41NDQsF90DR7dqeemMPwIMFwRalpXfvXt3vrGxMVVXV5cC9P79+xfr6+szkUjELSsrc4uy/avNxnwzOOYRyQBZL0dcr626nsIMkPDqfM+2bzAboAo47nmmFjCBRSAGPFqrw62GvwHMAdeNGK2SbwAAAABJRU5ErkJggg=='
  WMEURMPT.icon_type = 'iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAAZiS0dEAAAAAAAA+UO7fwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB94DDwolKCvyQLIAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAGcElEQVRYw82Xf1BU1xXHv/e9t7DsLiy6uwYEZBVYNGi7gwnYNpk6kx9TrcZJGe0v/cOONkPTJuMYJk5NGxUcp9ohOqZDU5wxk+CMQrEZneIv0Pwgmk6LElJKRECJbBaVZdld2F/33Xv6h0JqY/ghGSdn5s67950z53zeOWfuvQ+YhvT399/1/EZIVVXVlOzZZA07OjqwYMGCsfWKFSsKvF7vHCmlQVEU3eFw/PvkyZOfjepramqwdu3ar+erjh49OjZft25dmsvl+lOey3Uj1zV/OCd//kiOK38kNy/v8/z8/LqlS5cWjtpu2rTp68sAACxZsqTE5/O9ZdRU05wkBQ8nq7AlKBTUCe1Bwa6FBcJCxpItlt0bN24sLy0t5bW1tVizZs30AOrq6lhFefnPQpHoG3kWzfzTzEQqmqHBqDIm6bYTnYDWgE6H+2KsLaBzi8n40vPP/2r/9u07yOPxfKVvdTIAfX193/KHRt6Ya1Yf2ppvooctCuOxGOO6hFQ0xONxCB7HbHMCW5yq0fWIVK+GYoU93d0ftLe3exoaGnDo0KGpA1y8eBE9PT0JwyMjv4tFo0+9Ot+MLJPCyGxF2s83Q5s5C+ErbUhd8hTsqzZguONfSJAc6YkKuxjQLcFIPOvmzRs1LpfrK2Mo4wEUFhbC7XY7wrH4skdmGJBlUkgSwTAzDcmLv4+MDa9g9i9+i4zSCsx4/IdQLakAgeVYNMy3aIjz+BO7du3KHi+GMlH6A4FAciQay15k1aAxMIAh2nsZA8ffhIxHYXv6x2Cqhv7D+8EH+kGMIUkBnCaVVAatpaXl2WkBhMNhIiKYVQZltGUZA8VjANGdF/RFS9+ZmlUGBQyBQIBNC8DhcJBB06QnIqHfcW6ckwfHsxuhJCZhsLEOJHSk/eQ3SLClASAQAG9MMJ0ITqezf1oAnZ2dfcYEw4kPBzkicQJJID5wA6GPP0Tfn7fDU12B669vhf/9v4MH/IAEbkUlXRkWAGPe6urqvwEAjWVrCgDd3d0oKCiIWkxJZzxRIc/74oAuER0cxNV9W3Hz1F8hYMBg82n07NmMWCAEziV9MsTZtbCAyWTaxRiL3q4amzpATk4Odu/eLU0m07FEVf24tp9jKKaTlAQyGCFVDboQEIoGSkyCLiXCXODULY6IoE8cdvsRAGhtbb3/EgDA2bNnrzLIPwzEZfjIDc5UIaHr9KUhBeGfQ5xdCukwJxn/smjhwlsA4Ha77x/g4MGDAIBPOz49ojK0vTsk0RYURLqAzr8YggsEozod8AokGbTWWQ5HQ+Vrr9FE/icEWL9+PUZrmO10vhoXMlTrE8wflaRzCc4ldC4R45Kq+gWLEIWtKSl7m5qaeiaT3QkBfD4f9uzZAwA4ferUaavVWnk5LNAUEIwLASEEpBA4MyTxnwjBwNjbFy5cqJnsCTshgM1mQ1lZ2dj6xRdfOJCSktJ5IgR0hwmSS3SFJZpGiEkiWVFR8RZjTIzat7S03N99oL6+HiUlJaivr1cqKyuX+gf9z2mqmkKAFo1G3JIpdpuB4YUUicPDDB2cQcbiItVqfVfXdZ3r+vn02el7z507F7xzoiIzM3NyAI1NjXjyiScBAO5vuwu8Xm9TmnPuQ9YZqSACNIMGHgmTt8/D7BowoBPSMzNJMyYxoQsQEXo7L0NyXr169eqyvfv2BkbLabPZxgc4fvw4Vq5ceXsfmJeTPTAwcMj9ne9+b/3LLyPZaiWAGJiC4cAQDpSXw9N7DelZWVi7+SXMmp0BgMAUhdrOn2dVO3YARLWlvy59btvvtw1N6R5YXFScbU2xXlq18hnyDQ5STBcyyjmNDi4ldXZ2UnFxMZ1pbCQuJd2lF0L+46OPaJ5zXtxus5cT0fj91tvbOzYverTIaZtpa3Y/8ij13BqQfYEAfeb3f2l4gkG6dKWLPIHgPfWfB0N04v0PKCMjU8x1zt1W8qMSAwCsembV3SXo6upCbm4uAGDZD5altrS0HDGazU9v2PoKrA4HhJC411ZOBKiqAinlPT+KCFAU0HvvvMPeO3ZsKDEx8Zfefm8dACxfvhwNDQ1390BxUfGC9vb2PyqKstxsscBosYAkYTrCGCClRNDvh9D1GBGVhYZD+0f12v8aP/b4Y4sXLlrYBWDfeEfo/YEwAGCapjnsdnvWzp07r48pm5ubH/gv3JYtW/6/XvTAgj/IWN98+S9tiGRBMpU45gAAAABJRU5ErkJggg=='
  WMEURMPT.icon_blacklist = 'iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAAZiS0dEAAAAAAAA+UO7fwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB94DFxYbAagU5scAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAADGElEQVRYw+1Wz2tcZRQ959xvfmRmXqaZvDppaFeVwCwaCC4aEbswEA2oq1BdiP+CoFshUNRS3ApdiAih4M7NrIpkkY3ZCC4VAoVUE2USCAnOkDrJXBdv3us4tNTaNCjMhW9xv3t553zn/uABIxvZyP7H9r6k7/P5/FfFYnH8rMHfJPnALHihUPBSqfTt+fNTOivwCQA/SvJ8Pt8rlcY8iqIH1Wr1nbMi8AVJD7lcr1gc83K53KtWq16r1e7VJmsTzxv8dQBukkdR1FtfX/ednR1fWlryOI69Xp+68zzBKwB+I+m5XM5nZmbc3b3X6/nKyorX6/Xe9PQFv3Tx4ttP89GnaZzPQdQlc0koFApZwMxAkpJBsi8vv3h5+rQJLAB4TxQlUhIODw6zYKfTgckgyWV6geDNRqNhp0WgCOAWgIokmBkkotv9EwBAEu12GxQhiUlc7wJ447QIfATgJZOcEkhCMoBEq9XC8fFxokACDJFuZnkzuzk7OzvxrATmAXxCEpRoUio13B27u7tot9uJAiQkgTJKcklXQrCPn4XAOICvAUCSpy/sSw1R2N7eRqfTQafTgUzJfT+e5NuH8/NX3/q3BG4AmJHkopi+MCXicLRaLXS7XfzRbkPUQJyk6JJA2O1rr7z62FI8rlOvAfgUQFkSLRhCCJAMZg9PCAGHBwfY2NjAyclJRsAswCxQJjezSKZ4a2ur+SggPuJuDEATwIIktxAYzBAswILBQkAYIJDdp34IfyMYgsEsHEq6vra2dveflOADAAtEMlbqS5/VOPVlqFQqmIwnM1/ZlAjWzyflksbN7LPFxcXyk0pwDsB3A43HEELS+absVTJDHE9idXUVy8vL2Nvbwy/37w/Ek2kZ8GlmF0IIv25ubv4wCBiGCEwlywUwM2Zz3wdPfZMQQsDc3BwAII5jyB4qkIJLBEmmPslLwwoME/gZwF1Jr4kMNiS9KR01YX9/H41GA1EU4ejoKJuONCddWJJBlJP8neQ3TyIASddJvUwpBxJMj4RBP11Gg1uQQ/EsX3QA95rN5k+jP9mR/efsL/+DvMiiIfU+AAAAAElFTkSuQmCC'
  WMEURMPT.icon_delete = 'iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAIFElEQVRYhY2WXWwc1RXHf/fe2bHXWdY2dry249hmY9cmKnaSEqClReqH8lQnAtpKoRKV+GjFW1UUlUqlrUpT9QNeEEh9qYCH8kSCVJSkzYcigVpKA0F2nMRxkOO4tolDEvDa8e583dOHndmsvxBHGu3M7Nz7/51zzzn3Kqpst+vyZFcXodb33NbS8h0Jwxk3lXrtxrVrPHTuHMIXtxc6Orgvn6dYKn0vVVfX99nc3H8dY479+/Jl9i8sVL5Tyc0jtbX8qLubouP8qWvbtn3zs7PUpNNsaGiYXZyd7QkLheI3P/iA6AuI/zWfZ3s+j9648UN/aWnb0vw89R0dzJw7d9AJgoc/nJriF/PztwC+77o8ls+zpPULLfn8zy6cOIHruhhAiXDX7t1Xbs7M5KPFxeIDp059LsSr+TyDW7bg5HLDF44eHfB8HwF8z6Prvvsozs+/qYLgoZEYQjUBf+vrY8Fxns91dz89dvIkNXV1OCIorTGA+D5f3r37ys3p6QpEuIb4a1u2MJjP4+Zyw2PHjw+EQYA1BhEhFMEvFuncuZNiofCmG4YP/fH8efSg63Izih5o6e5+evTkSdx0GmUtVikUIEphUinO/f3vrZmOjgknk0m/s3Mnzhri2/J5Urnc8IXjxweiKEIZU54rDnWqpoaJU6eoq69/sBiGjw1mMmitNelsdujs229TU1uLQGWAAGItaI2uqeHcW2+1Zjo6JkwMoWPxV2Jxp7V1+OKxY2XxZHw8l43vndpaLr7/Ptp1v2uUQhvg6tTUjHYcRKnV4koRAVYE5bqcrYL4x44dvLh5M9vzeZxcbvji0aMDkbUorSviohRi7TIY4zhcm5qaIYpQ/cbwbEODXhC5bkQatNYowBFBa41WCp3ci4BSiO+zdWjoymeXL+cdY4obNm0avpiEXWustURKgbVYEcIYwsYOWmtJKZU7VCxeVQDPZbNsdpxGT2TSaJ3VcfY7WkMsbuJfJQIi2CBg69DQJQVXLxw9eq8VqeRMBGVxpYhElolH1opRql/B+OM3btzqA89ls3SugFjmeQyh4ghhLQCO6xL4PjoJe+J9WQyUwiYwIAb6gfGfXL+OT1UjAvhdfT2dxjR6Sk0ayAIVzxHBxOIKEBG0UkgMZa1FKYVUCS+LBIiGfgPjT8birARIIDY7TqMPyyCULue8EUGg4rGuqhprLRJ7nyReIu5Av4bxx69fJ6jSWwUA8PsYogSTCrJJR1RQLsmqgdVlpqqEk1yQzxFfFyCB6HCcxlIUTRpjsknoE5DE+8QqAPEyCGBFRCvV76wj/rkAAM9kMvTV1jZ4QTDmOE6usv6xePXuWN1sFBCGYTHluoM3Pe/iTwuFdfePlR11mdXW19PS2fmZaH156syZnDEGRXn9wxURiLi1BIG1tPf1XRVrp2p8n2hkZF0Nvd4ff+jo4P7eXpq6u4enL1y4R5QiuUKRygYTWrvs2SoFWvO/8+e72vr6Jhuy2fTBwcF1hdZcgv3t7ezo7aW+vX34/SNHBogijOPcCn9SCQBal0stnizZxKwIvufx1T17rlybns6XCoXiD0ZGVh1qVgH8tq2Nu3t7yba3D59aTzyuhLVyINlJBSCG+NqDD175ZGoqXywUio+cObNqXMV+09bG3T091Le3D7935MiARBE6Flci5fKL+8F6VQBxKcatV0QIPI/7E4j5+eIPz55dDfBsaytf6e2lsb19+D+HDw9IleeqqgVXC1c8EUHFDahSCVX9wMYQX48hlhYWio+OjkIy189bWtjR00N9W9vwvw4dGgjDEIzBilT6uI2TTJYnXlGsnROlyu+sRZJvlCqPi0FwXU4ePNja3Nk5UZPJpF/ZurUM0A7cs3kz6ebmD98+dGggCENslXgYZ30Y72phEl5rRawdUEp9KYyiQqVCrC2LJlUSvwMwrsuJAwdamzdtmkin02ZXXR36jlQKz9pHR959d1sURYgxZeFYPPFIkucykCil+j346FIYFlJKdYcihVCk/H/ieTI22RFF0KkU7xw+3Kpc99ddjoMjwNzMzOBioYAxprykcRarmFxBOfNFCOPeDoz/anGRENiXTn+aM6bbh8kIsgqI4kNIpUPGOaJjmEtjYwOBtWgRobi4+F4inghWDhexR3H4RYn0K5HxZ2JxgD8Xi8xa+6kj0i3WFkJrK4eQKI5aMieUO2ngeadsEJSP5c9mMsyLHAe+zVpWXgJRUdQfRtH4c3FkVtqPgY5UqtEaM4nW2aQy1rCxNNz5pueVob4B7AICrU9o1/2WqoqGWIstlcRpauq7rbf34gebNjEfRaRWTG4BH9i1sMDC6GhDcPXqpHbd+qRvJHOJ74/pKLrzEvAqoFKpFM+/9BK3A/OnT3PjwIF/hteu7VKuW26xYRjknnpqR2ZwcDS1cWMqZa1WUMPqLiqA52tto8XFaGl0tOXjF188SxjejjFIGKLS6TNNQ0MDme3bKW3cyC/37UN1dnby8ssvM7+wsEM5zl2kUk3X33jjyaWRkTtSTU1e8969p52mpiXxPAcRobyDNq4D8CkQohTKda0tFtUnr79+rz89vaG2p+fj5r17/6KMmZUgGM2k06f3799f3o5FRGNtk/h+F77f3rRnz0jzww9/JCJ14nmNUio1xiIbKHu/nrUAPiKL4nmijJHcE08MK61vShTdFM/LSxDUAB8Tn+ac6elpJiYmbEtLyzFr7TEA8X0tvq9jb90qgdoVz2tZAJQAQQQplQIpv7PxhVKKubk5xsfH+T+H8K+bjXuKEwAAAABJRU5ErkJggg=='
  WMEURMPT.icon_priority = 'iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAAZiS0dEAP8AogAA6dv1/QAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB94EHQghL5pOh38AAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAADiklEQVRYw+2XT2xUVRTGf+e9N/PaqUw7rdOKItLYmnRIrTqhBklcTMLKhStcdAGGRjYluOgKFoQEF6QxbokmJg4sZOsGdyxM/BtRokgjJDYhVWkIf1pDoR3ePSzev3lvZuhQQTe9yc28+9695/vu951z3xvYaP9zk/Uu1JO4QAULsDgn77GynjjWusA/YpxV5jCcRTkLzOmnjP8nCugMeYRzOJRxUBzARrA5j1CR/Sw9WQVqTGMoY1AMEnRFKSNMP1EF9BglHH7DARwUG4muHQQbsNgu73Kp3ZjOI9E1nMEAHvzl9cmXS6/TkevgrYEfpcdcDfU8A7z82C3Qw0xjKGHQmmdx+KcyH37xBx98fomP/3yb+3YvgS0l/ax9K9oioNMMY5jCYGOQG9rPtVtx1V25epOau5UgH2xgSqsMPxYC+j4OhoN4DGIAAzlWcDN2NKfQ3YV9fxkMoIAyCBzUU2tbvLYCHmMYDgWBQSHv3SKfy0RTBjf3kLm7QEgQD4BDwNi/IqD7cfA4HQTWCMDAyOZOP4BlMdhrIauLMQEN5iqntfpwFaw16M2gjEQ1rxEAO3r/AaC3UGBr5m/qyUVnA4wgzKyLgO5jF4bJOl99aQOQHe7vvv893Ty/ejH2v56Ib8WkVtn1SAT0HVwMRzHk63aUACjcm6fYV6C/+DT5m+fr5Y9V8InnEY5qFbd9BWz2YKikZG3Y5c7SFl56dlNy517TNRWEPW0R0Am6geMYnHTipftoX40tnfeSxDTV/VxwgONapbsdBU4gbPPZJBMvoYJCuec2o4XllgQDNUL7tiGceOjLSCfYCXwTQEjE3X/lNl5nHTQrCLX4WXpufE8RBHhD9vJtAwGdIAdcAIYTBKxU4Iz/eweL75cKZLIwXryNm/Vag4cELAThCvCK7GU5bcERYCgCj5g1T8Bjc6NMfVfkwFdFqotvYjyal2K8VoIjaijAinNAJxgAdgfAkjCoSYYveHkuLG2Kpv2w+AwrT73YkCNNiEhgw249xUC9ArmgtziVkrvr7xCGXnguevzq2HbcTDZJtJUiIZ76eCGBeeByCjL9MRJ1WV7kZMVl9pefmb34K1Ov2VjXZ5uXYnwuaDRWLiPMp5OwBHwCTY7NMCvSCdaVRztzyN1rrSugcfw1Dgdkn//Zli7DLmAA6EuoEBKwmgTPNCnR+nvxWLC5QYYFmeTOxl+yjRa2B+5IidtmKn3pAAAAAElFTkSuQmCC'
  WMEURMPT.icon_checked = 'iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAAZiS0dEAAAAAAAA+UO7fwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB94FGw0UDITYgDwAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAC3UlEQVRYw8WXS0gVURjHf2fu9VXakAsXWmRFWFKbcFFIhQhREzKlBC4K2rUIIYKEoE0PCCIiaZctKrIiKJmCSRdtEoMeWiCIFr0QwQcZU5aPe+eeNufGcF/O9T46cBbnzDfz/f/f+f7fNwf+8xC5/LhumwVAEzDhGNbLRDZajgneAB4BF3TbLM4rAN02rwFH1fKrY1jzeQOg22YrcAIIALNAV95yQLfNGuAFUKG2+hzD2p3MPhcRuKWcS7U+mcpYyzL788AOT3SfO4Y1mOqdYMy6HtgJuOk6L9hdVSXdSJsIaDJ6tL/PvRoEmoHHfgH0AivTph7UKGhYgwhoSCkRQhDqGyc8MHkaiADbgOGlABQA80Ah0A189HtEhfvWbQjWVbQAQSEE0pVueHimh7BsBEJAiZ8IRJMmBNwFniaIUNxYcaauOFhfeUdo4p+tCIj+yPhsO9CvpOg7B6IjmgPhJc9+V1U1cMhDIgTcC7+dcvxELxsquOxxLoAvwE2/L2sZym4LsD9m+5JjWG5eAABnY9hPO4Z1Oy0BxSFaW6qVduzpFMXBSuAX8Bp4AHQ7hvXdw74cOOBxDnAxXQZxESg5tb1QOQcoAxqBTuCNbpuHPaatMfL6o9STGQBRFKcaqeZ6oEu3zStqf6+qGdHxUHW+zADMdbxflK6cT9AxpSpWbbptdgO1Mc97HcNazBiAO/oj8rPpSYtjWAKoVjkg1JSK9UFgk6d4fQaGlpPFKVXgGNY31aCeJfl/iK5HgNGsA1AgwsDxFAwjwJCyyz4ABWIMaFfNSsY8XgDeLbeQ+C5EjmH1AJYnF/A0r5GcA1CjTTn0KsMFxvICwDGsaeB6TPuOOIY1k00Acok2fFUVnKg0O5PYhdK9mgWBCWAVYCttJ4xQoLZ8dVHzxq3uJ2dq4f6H0SQkyoAjwCLQAAz4ATTpKb3ZmnPAZr/d8BhQk0BqmVx+J9X/pe+bUbZvSynJ/AUWE+o2p0KuHwAAAABJRU5ErkJggg=='
  WMEURMPT.icon_unchecked = 'iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAAZiS0dEAAAAAAAA+UO7fwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB94FGw0UMdywzC0AAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAAy0lEQVRYw+3WMWoCQRTG8Z9BhRR6BUuDbargBWy8g0WqHE4PZJFaEISQoLjK2qywCMrorkTw/eHBzMCb+d6bgfkIguDZaZzMh/jAvqb9X/CNaWrCL/KaY4/BuQObpXELG7Qxw7yo4BZydPGJDK8pSU0s8Ydxae2WaKCHFX7wntKBMsc3sKtw/7vUR/KvhIAQEAJCQAgIAQ8pIK/4DR/JUk3IKW18YVTREXUKJ7S9JnFxB0+4xltqByboF4l1ue5F4S+TbPm5tSpcLOYAHptFzbynhPsAAAAASUVORK5CYII='
  WMEURMPT.icon_ge = 'iVBORw0KGgoAAAANSUhEUgAAACAAAAAYCAYAAACbU/80AAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB94HFgoXEUEWIh4AAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAJNElEQVRIx4WWaXDV5RXGn/N//+vdcm/2/Q5JzEIICASERnEBHGilY0dGg9hRqaV2iq2tVWudlnE6Mk7VDqPWGZUySl0KBavV1mVwSQUpBBoJCVkEzEq2m4R7c+/97+/bD06rXdTz8Xw485vnzDnPQysX78VUADhz+AY0rvgjWcKhs0c3cwA4+OY5ZXw2XZKY5TWpObvEdiwxmTClscm52c6u4Y+HTj09AvRmAUAIQUXxn9Lk0KMcAOrqfoC+vt/iq0quXB7Akac2IK92N3Ud2SiISABA5aIXl2/f+dHG5kWx1fPrQ+W1VSE5GIpxiTyyTEcMjxYljn9U+cGhE+P7O/92/wdEZAIQlY0/k4a6H+KrrlkGm+7CQO+jXwpAAADjNwTzJ+LT1r0Fwcr6Lfm52lZZZlWaypAbZSguUFFYoKKyVEFtdQgVJTpUFejuS8wcfOfc3t2/63gM/uO9ABAu2kZzE0+Ihqa70XPq4a8C+DmEeJCISBhFT85rXl76YCxqbMqPGfB9wuiYieFRS8ykbOiah1CAI2g4aF4UoY1fj6M6HsInQ0m89c6Zo7t/337v1PDOtk9HXw9gH4or7sT48M4vBGC7XtrJljaVcuCB/B/eufzhG79Vc+Pm6y7CN9fFsX51sVhzeQHmxUNkuQxT05wyGYFk0qbu3mlxsmsCBfkqNS8qQGGeXp4T0RYe6yk+7mePjwHdANYjnXr+SxVgfz7wtACA79/1ix/fdlPdj1a1VCAv10DAkIWhM8SiMubXGtRYG4RtSjQ46kKWiVRF0PBoEj0fT6KyzMDShQWk61JJ0GCx9qOJ94HRbNWCVTQ72YHiys1IJ0/9fwAAWLfx5ZYtm2sfbqzLDZuWj6mEKSzbIcCH4B4ATqWFGqriGiXTPnrPZUnAR0AjOj82S5lMFgvq86iyLISsaTc6Imf0bP/7R2cnOwD9JrhMh5/p+CKAtYFbb1t/f8283FVvt83gqedHxeHjGYxMcmKShGiYwMDJsjzEcoiqKxUk53zqO5OG8FyoqofB4SkEDQkXLyikgC5heiaVf+RDqQ34eHply3oaOP34F65A2nb3HcVZ01/9zAvn8MyLQzjdb2J0wqe+T1y8d8LH+ycI56cAwX3YtoeSQobvtBbg2qsLIDEJHpfgcaJX/tqLt97tRzikoKw4tOyKNfMXA8BTD1+NHb/ei8HBQQBAZ2cnRkZGPvsDp3tn15BkFg6eB4hFRGWFhryYAl1jMC3CqbMCYxM+FszzUBfn0AM+KooZttxQAkWxceD1NByLYXR8hp59qV3Mzk7T+YkZjE8mFgPagYXLV3uPP7Fb6e7uFm1tbcK2bV5WViYAoL29HXIy49yTTNoaSWEEDQm+58OxfXgOh2fbyLg+psY99PZZaKzmWLEYKC+UUFmq4ZaNFQhpDva/msHAMMfp/nGMnR8FkQ3T8moAWweQvmPbFvfzsh88eJANDg768Xgcspm1qgEGJnHh+y6ZpiMyaQeyLMF1fciyBNvxMZu0cLrfQnuHj3WXa1jaGEBpoYpbNs5DbpjjD6+Y6Oy6QCMj05AVjnBYi3/71l9etmf3A6cOHf57oLgoP1lTUzNDRO6aNWv8rVu34uzZs6DaJY8IDg1MjnCmhCRVDYpgwKBgSIOuK4IxBo9zylqOmE5YNJfMiryYRVeu0LH20hjq5gUAAEf/MYx9Lx/Dh8d6MD2TgqJI7rbbVyeuumK+nUrZvqoqA6qqnggGgwebmpoORyKRLABQ44pHsqYNTZbDkqKFwVhAMKaSLGtQFEVIEsEXnGzHF55jk2WaIp1OkyzNoSZOWNOSh5VL8hCNykimTHScHBBth3vFqdMj0vqrG7C8eR7SGQeMSVBVFeFw+EI0Gt1dVlb2UENDwxQrqbiy1DSdhabpydmsL0zHhRAgiQDX9WE5DmzLJtexwD2TCCYUZpNlZTAyNo2TXSPo7BpFMpVEMMRQXBhCYX6IJhNpMgwJsZiGdDoLx7Fh2zZc19WFECuFEH3PPfdch3xhOvECJ/26vBxVLyzSyHIYpmczmJnOQlVVaIYMRgB8D5zb4J4D37egqjYIPlKpNI6fHEdPbx/ycxmqq/IoFDCgKAx5uUEILiBJBCKC53k8nU5LsiwjEoksEUI8Lw/1H+hpWra58+ZNF629oqUK0zO2eO/QGB1qT2AikULqgg/BAVkBFMYhkQsIB+BZSDARDgg4jof0XBqJaQv95yahqQxrr6pFSXEOXI+DiABAEJFgjEGWZTDGJgG4MjAwW1mqvtrUEFsbLw+itEBFaZGCy1bk4Uj7JI59NI3RiTRMy4WVdeDYJnzfghAWuG/B87LwnTRIuAiHdbgeRyQko6IsAl1jyGR9AcAXQpAkScwwDITD4Xej0eg+IuIMAGyzbLC8vGChYag1miKTIoMX5WvUVB+lry3Nx/zqIEUjAprikSTZUCSTVNmDxlxoiotIkCFeHkFNdQFUWcb8ukI0LSgWAvB9X3AiKIwxSdd1RCKRfWVlZfe0tLT0AIAMAENDL0y+uDf8kK6iYdmSeGU0x5AyGZtz4UuKTLSgLoy6KgMZpwKptIPZmRQuJOdgmzZ87kFmABEXvf2TggTnDQ2FXDdU2TRdWZIIjDFomjYSDoefra2tfeySSy6ZAoD9+/cTa73pV1JX53ticvz4gO2Vj2q6dFk0Rw+Zpo09e9u919/uwVRiDh53QfCFLHEoCoSmCqEbjJMk+FQi5Z/qHudjE3Osob6QxeNR5rqciIgrijJsGMbeWCx2/+bNm/fs2rUrCwB79uyhTZs2CQKAv7zyOn3j2msEADTM33TztRuWPBkIqoG9f+pA/5kpRCI6AgEZAU1C0FChqAoAH1nTwdycBe5xFBSEsay5Ag31+T4XIul74rSqqm8EAoG3WltbO4PB4L/f8WuvvYYNGzZ8LhMCaHvzDbp83XoBgC6++Pp7AuHQdxMz2fyxsVnJdrni+xyAAJMkSBIDQfi+L1xZIq+hvsBZdWlVtqYm/6wssw+zpnvE0ANdt9/+vbHPe8B9992HHTt2/Osq/hMAqAfQ+1lQ0FsaK8pzW8ys1+JzquWQJAH4nAuQ4IoEPpETMQbqakvOrL6qurd5afFIJKKPLG3eeOG/Pb+1tRXbt29HQ0PD/+SBfwLs6UJD9IUzMgAAAABJRU5ErkJggg=='
  WMEURMPT.icon_export = 'iVBORw0KGgoAAAANSUhEUgAAAFAAAABQCAYAAACOEfKtAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3wgBFAggT+iJkgAAAB1pVFh0Q29tbWVudAAAAAAAQ3JlYXRlZCB3aXRoIEdJTVBkLmUHAAADUklEQVR42u2dTWsTURSGn5lOrEoJVYsff0AqUhHEreBW40IR/FiJKze6cV2NuhFdiFgQXLgQf0ARXIk7t3UhLYp/QBTFEksbmibjYk4kxHSMucn96JwXhtAmTU6fOfecc++cuYmwoxIQ459aQMPkDSILRk4CN4EZDwEuAQ+BZTxVCbgH/ACaHh4/gUdykr3UODAvxqaeHkYQY1STwBXg9iAQEwcG14AFYMXBZ1c2ifttiAB3/icmugC4AFwWI1OLoeRlF7waUDaF6ALgihhXd1CydOo5cNUUoqsYmDr63E6I0wKxZhITi5xEGsB9U4hFz8LLMlQHhqhljCFEBWgIUQEaQlSAhhAVoCHEpMCgJoBdspjQrTUpccgptleBapEBHpPpXd6cvJQzYzkMxEUGWAZO9vG6U3klYJEBDpIDWt1/U5Qk0iJbvq8N+42L4oENsmsfMNi1mRjYAM4UFWC7PKkOOOrGgRdF9sBOT3QaRFUKUAEqQAWoUoAKUAH2rW3ADux0km05gBGwBzgnj5ECHGwadR64AUz5BjEEgBGwl2xR87pvEENJIjFwwEeIIWVhLyGOejVmA7jI8DqxOiECPAG+465ZaeQA273Io/JE5xCTnMA9JsZGjkfIPmB7DsQImAO+uYDYC+AYWe9cBTgC7HQIMQH2AwdzPPGaQL4FfLUNMenhedPAXeAE2fVP14km/sdzU8AF+XnWticmPbyvIvCmAsrQZeCseOBjiYlOzm4sw2UiwHn9buAScBqL13q6AbaAz7i5BcFU68Ai8H4Emb9vgE3gNfBOhsFGIPDqwBuJ3R9dxsBUDJjtysKuEsmYZNhDYkcevCrwwfZJTzYpfpeAT/IPuJ4pzQBPgaO+wcsrpFMxxvUQXpfMWvcRXmiLCd7BswGw1+2ur+T3wcML0QO9gmdjNWaYWgXe+gQvJIBrHXWeN/BCAdiUwn7eN3ghAEzJGiOfAV9sTtG2kgf+kiP10bgQAKY+G6e9MQpQASpABahSgApQASpAlQJUgApQAaoUoAIMSC7WA/M2vPFVk2zSseYCYD8b3vimCeB4rxHrAmC/G94EEe4Sn4zRJPK3RrbhjWPVyJo5W6P2QNMNb3zVIvAAaNi6faHE1iqZ/nyNxm/UEhZ+/DhJcwAAAABJRU5ErkJggg=='
  WMEURMPT.icon_pur = 'iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4gYGDREP9s0XhwAAABl0RVh0Q29tbWVudABDcmVhdGVkIHdpdGggR0lNUFeBDhcAAAWzSURBVFjDzVd9TFNXFP/d19cBpVihrciHUgSKiG4NCihqRqJuE0Ezif6x4BKTOVMxMWY6TbZsKjNmuKBGjXMsMZv4hyLOqMNPwA/8WLIqujEUQa1SX41ALcVS2vfe2R+MRjY+xRlvcnPvu7/zzvm9c8499z5gGM1ut/cY34i2Z8+eIcmzwQrW1dUhKSnJ/5ydnZ0sCMJYWZaVHMeJer3+z1OnTj3sxktKSpCXl/dqvurIkSP++ZIlS0YbjcbdCUbjk3jj+Pa4xPHP44yJz+MTEh4nJiaWZmZmpnTLrl69+tV5AACmTp2a29LS8nMgr1CNDeIgh72P6wHzuzD7SjxwS3BLcmeIWl24bNmyArPZ7Dt06BAWL148PAKlpaXsm4KCj1wdnr0Jaj64JnK3H4vkWhCpaMXvvgQAQMaTlbjlFH1qVeCa/PwVOzdu3EQ2m61P3YrBEGhqanrb4Xq+NzZYEX4rqst4BGtGCHNDIB2ICCHMjXao8EidhenyKcV9V2fKvcbGS7W1tbby8nIcOHCgV91cf4avX7+OOXPmvOX1+cyM5HFS9Co/VrEKEEgHoGus/DwIEQoHAKBKvwu6AC7c4Xi2kYiQlZXVp41+CaSkpMBkMundnd65U0KVMChb/VjI5HdhP5EJAHh8ZBpCZ86DIIX68fFqHl6fd9aWLVti+rPBDeR+p9MZ0uHpjKnS78JJ71T/+pgltZC9HthPZIIpeIzOPt/jvdPanVAw8BaL5cNhEXC73UREvYP+depDOYPT6WTDIqDX60nJ8/LH7at6rD/6KQlcQBBGZ58HSaI/HC82kQgGg8E+LAL19fVNgW8pT15u9XXlBX8XAOC6ednv9siF1+C4+GsPfIqQDzAmFBcX/9LlLBo6gcbGRiQnJ3vUqqCzNo8kA4AghQEAJhSF9ZBNKgzu2jliVz144JagUqm2MMY8AMAYGzqBuLg4FBYWyiqV6liAQnEz1roCAmkHrBsZQj46JPpDr9MdBICampqXDwEAVFZW3meQv232yu7ByN9wiQgOCvxh0sSJTwHAZDK9PIF9+/YBAG7X3T6oYLilv2fuP2kbzQhS8jWj9Pryom3baCD9AxJYunQpumMYYzB87ZVk15Sm3klMt5nRQeTWjBixvaKi4t5gvDUggZaWFmzduhUAcOb06TMajabojlvqVfavDoKSsf1Xr14t+d9uPCUl+6NTJk++k5SYSOHzqvw9dUIiGY1G6fDhwxkvylsslpe7D5SVlSE3NxdlZWVcUVFRpqPVsZxXKEYQwHs8HSaZcTqtksEa+z1SrctR52OQO73SSI3mvCiKok8Ur0RERmyvqqpq++dERXR09OAInKs4h9mzZgMATO+YkgVBqBhtiA3XhI4EEcArefg63CQ02ZiOB5pFQkR0NPGBQUwSJRARrPV3IPt8xYsWLVq7fcd2Z3c4tVpt/wSOHz+OnJycrjowLi6mubn5gGlaxvSl69YhRKMhgBgYh3bnM/xYUACb9QEixoxB3mdrMCoyCgCBcRzdunKF7dm0CSA6ZF5pXr7hqw3PhhTr9LT0GM0IzY0FOfOppbWVOkVJ9vh81N19skz19fWUnp5OZ8+dI58sUw9ckuTfrl2jcYZxXp1WV0BE/Se81Wr1z9NS0wzaMG21aUoq3XvaLDc5nfTQ4fhPt7W10Y27DWRztvWKP25z0cmLlygqKlqKNcRuyF2YqwSABfMX9AxBQ0MD4uPjAQBzP5g70mKxHAwMDn7vky++hEavhyTJ6K2UEwEKBQdZlvs8rTkOdOHoUXbh2LFnAQEBnwp2oRQAsrKyUF5e3jMH0tPSk2pra7/jOC4rWK1GoFoNkmlY25YxQJZltDkckESxk4jWutpdO7tx/kXhGTNnTJ44aWIDgB39HaEvR4QBAON5Xq/T6cZs3rz5kR+srq5+7b9w69ev/3e86LUZf5223vz2N1n2qCrgsdjvAAAAAElFTkSuQmCC'
  WMEURMPT.icon_csv = 'iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAQAAABpN6lAAAAAAnNCSVQICFXsRgQAAAAJcEhZcwAARCQAAEQkAUBnxFQAAAAZdEVYdFNvZnR3YXJlAHd3dy5pbmtzY2FwZS5vcmeb7jwaAAAIR0lEQVR42u2daWwVVRTHp6XUNipLWWQJRhYjpRb67n9eS4uSR4FE+EBJBDf2iDUEaAgSKCqyCEpQZJESI7gE0QiUCpE21rCXrWWRpYAKFSqYAKWFsi8t44eW9t377sybebO9lzc9n9re5ZzfzNx77rmbIOj+QSwykIMtOILLeATJQHmEk/gaY9BFCNYfZCAPtw01mg9iNeKCz/iXsM900xvlCkYHk/HNkWuh8Y9lB9oHh/ndcNoG8yVIKEcP+833oNIm8yVIuAaPveYn4qaN5kuQcB9v2Wd+a5yz2fy6XmGGPeZHYlcQmF8nH9kBYKwfpWpwBqfr5VS9nGyQ0no50SDH6+VYgxytlwoVCGZZbX4M/pVVpgBZSEOsYXU1wwrU+kXwobUApsuoUYHXTKlvroq34H3rzI/ARa4K+WhrWoN7RwWCmVYBcHOrL8OTJta5XlVzmG0NgE+43VFfU+tcrrJHsAIBSjkVLzO5zjmqO8Vs81uAB5xqe5lca5YGv8BcBGjLqfIOokwGMEKTa2QmAiRxKtxn+mc3SKN3mG2tKitMB5Cm2UE2CwGGcipbaDqA3gGMEbLDHYA5rlFIATDDQQ4xABI+CHcARg+WQxCAsSGTkARgZFsQogAkjAl3AA8wILwBSKhGYngDkHABHcMbgIQSNAlvABKywh3ADXQIRQBJBs4kbQhFADF4aCCCtJADIAgoDJLZRNsAdMYNwwAUhiAAQUA8SgwCUI3IEAQgCIhANwzDWEXJxGRMwyLko1xhqV7XkASgWVeCozIAuocFAEFAU6wKawCCgBa4FdYABAEHwx3A5nAHsMkB4ABwADgAHAAOAAeAA0AFABKPpdiNPxWEt0q0UjGHWVKKDWSiJ8pAABiPu0GzCF6liAfd7QwCAGJo4NE6yTcKwC8hab4ECSnGALigepvKJRxDIdmJM6pWcV/CduSQiSQT88RvsQ33uXsBLzUIfyfSda8UTHiUTDQGgJop5jwy1tXGO1dqnDiE5HKNkiBhtzuJrSexJXkHRVSq5fT/ccp3n6AnpjFFtyeY/UqfWgNgnXwoUXyTNxcrviGrVSTKvRqyH5jSFvg0dW8zga7r6rthYwBccysuLxCHcXb1PauQIQJXvT8AgQpTu/r7lEaVRdK1+CFGADjv8rNLE8t8ntkwxfSJTOpk6rOKxT3q/38xuJdYC+CW+IJfZ+MIk2eVcnpxEtOMzWbK20HhYdYi46ylAES/e7VTmrH7unybPsbjZDdcH2B0mUVpkMF4q5KVALb4pkyNI+mYio9JpjgwNVYQxMFMnru0g9qzrTgd+SgUVyArubMgCBE+uwFr0do7h9t7dfjDlGbU2zPdUgDkZTqVJwoLqSmnmySXfSVFZv8A1lKm/ko4G+7JCKadb/AGyF6mtCIrAez36cP3qvAXVjIlH1KRZy3zkRQ04Jzj/ffkVqixEACZwjRei1T5iuvoXK6+Kqa2K+iuENMaAPShNBildTiu7w2gVtb16qjK9ZVw3Kfs1vjMX166KwR5PJVNtyfcHYSmAbgiRFAp5qocLdxLeIpTfnvkcHeccV91IbLucAaymWkbqq0EUMSkWK96lL6Ar0xyZ7JGdit0MVNbHiRI4iSqdxjAzWkWAHGjH3dHXu4mPSerUD+Z8R7TFWKq70eIpZYCIF8xKao1jNEPpzwj6wb1xjVuk0t1hWIyJFQyH2GZtQC+YFJc1hSmKEt6XhbBK9wcPzIex226BXD1kKnJtDbgeybFHo2RmkoyxXscL+/ty3SF2/Ee9fsMqwEwbjC+C2SFNsnkRW5dff0HtzDP7Vb1AEwD8AfjBr0bYMzubwxna0uI5vUGdFfoSh3ehPIlaq0GUJPUglE68KNzit2dmPrOc1qdEoUh9GjZss3zBOmBqCCQkToi+EuY+nbzAq50xJFKv8EGAOQbn1STmWiN3DFXh30AbGVKOsOtcSTfjIRohfGEiWOBe77zLqQn8uo/hSpsx2Iyrs5no2SCILh6YKVXf39HHEx1cjEyX/RPMh/AQAXcpgZEZApPatEYqCQ+2xlIfEND1sHVH+NJOt2aCIJbbgfAVYG7jlfxFBFTAdynuyJuFc2ZPFW0/8bN87mcOaQ3N/05uwBI+Id9epy81JwxKfCX3p2gMA85l/MBvKjY4pgeFj/k8rPPBr9r264s7lKa7+WUP9NeABIuutPUzwuIr/r5YJQ9ykc9fU6kEvfZDUBxaszdjun09rhSZZ/9YJmDuLwBjmLc5jZ+jlMzCECNXwS1KBbnoB+6p8YlRLs7ickYimko4qp3FBPcSd4B7T5Pixniz6qcptPiINHTKP4CMWS+MQBOmDJ3X4FiUoADOKsUDtMndBwhYADkyxBdHvFQPvqkCUBiS/wXigDYeUUdi6RIvKopjKB6+mT28CYGLpPzRIkeTMVCBdnImz9SzGGSkPlkhPLL7yyUdAA4ABwADgAHgAPAAeAAcAA4ABwADgAHgFEAbDlYWReArRyNOwdenC1Ha+sCwLsLKfArQOw5XF2H+V04+lbpKdCW4/V16Ps6R9tSfUXacMGCDm1/42ibq69IG67YCFjXcdxQqr7r+uy4ZCVATTsyu8vqI8k6r2y0/pqdAPXsimKuntv0F23xRUsBPaQs2QtAh+gv3sKrtjTr1hzpmIH9svoVGVONmsvW7DhT4Jzf225TjQEQTNftaZHVxr1qwXHhojbZi2gjvzb7r9zUJuWG91I2X7qqTcp0DIEVENh37a422YlW5nU7uUFufA2Woam5fa+1V29rk82It8YBsebydS1ShTXoY60XFosM5GALjuCyX4fErNf9IkqwCYuRrjVI8z99NOgo2/BpDwAAAABJRU5ErkJggg=='
  WMEURMPT.shuffleArray = function (array) {
    for (let i = array.length - 1; i > 0; i--) {
      const j = Math.floor(Math.random() * (i + 1))
      const temp = array[i]
      array[i] = array[j]
      array[j] = temp
    }
    return array
  }

  WMEURMPT.getElementsByClassName = function (classname, node) {
    if (!node) {
      node = document.getElementsByTagName('body')[0]
    }
    let a = []
    const els = node.getElementsByTagName('*')
    if (els instanceof HTMLCollection) {
      a = Array.from(els)
        .filter(elem => elem.classList.contains(classname))
    }
    return a
  }

  WMEURMPT.getElementByDataID = function (dID, node) {
    if (!node) {
      node = document.getElementsByTagName('body')[0]
    }
    let a = []
    const els = node.getElementsByTagName('*')
    if (els instanceof HTMLCollection) {
      a = Array.from(els)
        .filter(elem => elem.getAttribute('data-id') === dID)
    }
    return a
  }

  WMEURMPT.removeChildElements = function (node) {
    if (node.id !== '') {
      delete WMEURMPT.dom[node.id]
    }
    while (node.firstChild) {
      WMEURMPT.removeChildElements(node.firstChild)
      node.removeChild(node.firstChild)
    }
  }

  WMEURMPT.createElement = function (type, id) {
    const el = document.createElement(type)
    if (typeof id !== 'undefined' && id != null) {
      el.id = id
      WMEURMPT.dom[id] = el
    }
    return el
  }

  WMEURMPT.getId = function (node) {
    if (Object.prototype.hasOwnProperty.call(WMEURMPT.dom, node) === true && WMEURMPT.dom[node] !== null) {
      return WMEURMPT.dom[node]
    }
    const el = document.getElementById(node)
    if (el !== null) {
      WMEURMPT.dom[node] = el
    }
    return el
  }

  WMEURMPT.logDebug = function (msg, obj) {
    if (WMEURMPT.isDebug) {
      WMEURMPT.log('UR-MP Tracking - DEBUG - ' + msg, obj)
    }
  }

  WMEURMPT.log = function (msg, obj) {
    if (obj == null) {
      console.log('UR-MP Tracking v' + WMEURMPT.urmpt_version + ' - ' + msg)
    } else {
      console.debug('UR-MP Tracking v' + WMEURMPT.urmpt_version + ' - ' + msg + ' ', obj)
    }
  }

  WMEURMPT.setTimeoutArgs = function (func, args, delay) {
    window.setTimeout((function () {
      const jsonArgs = JSON.stringify(args)
      return function () {
        const args = JSON.parse(jsonArgs)
        func.apply(this, args)
      }
    }()), delay)
  }

  WMEURMPT.getFunctionWithArgs = function (func, args) {
    return (function () {
      const jsonArgs = JSON.stringify(args)
      return function () {
        const args = JSON.parse(jsonArgs)
        func.apply(this, args)
      }
    }())
  }

  WMEURMPT.invertObject = function (obj) {
    const newObj = {}
    for (const prop in obj) {
      if (Object.prototype.hasOwnProperty.call(obj, prop)) {
        newObj[obj[prop]] = prop
      }
    }
    return newObj
  }

  WMEURMPT.listToObject = function (arr) {
    const o = {}
    for (let i = 0; i < arr.length; ++i) {
      o[arr[i].id] = i
    }
    return o
  }

  WMEURMPT.objectToList = function (arr) {
    const l = []
    for (const i in arr) {
      l.push(arr[i])
    }
    l.sort()
    return l
  }

  WMEURMPT.getDuration = function (ts) {
    const aDate = new Date()
    const now = aDate.getTime()
    const duration = now - ts
    aDate.setHours(0)
    aDate.setMinutes(0)
    aDate.setSeconds(0)
    aDate.setMilliseconds(0)
    const startOfDay = aDate.getTime()
    if (duration < now - startOfDay) {
      return 0
    }
    return Math.ceil((duration - (now - startOfDay)) / 86400000)
  }

  WMEURMPT.escapeHtml = function (text) {
    if (WMEURMPT.policySanitizeHTML !== null) {
      return WMEURMPT.policySanitizeHTML.createHTML(text)
    } else {
      return text.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;').replace(/'/g, '&#039;')
    }
  }

  WMEURMPT.convertHtml = function (text) {
    if (WMEURMPT.policySafeHTML !== null) {
      return WMEURMPT.policySafeHTML.createHTML(text)
    } else {
      return text
    }
  }

  WMEURMPT.decimalToHex = function (d, padding) {
    let hex = Number(d).toString(16)
    padding = typeof padding === 'undefined' || padding === null ? padding = 2 : padding
    while (hex.length < padding) {
      hex = '0' + hex
    }
    return hex
  }

  WMEURMPT.isDescendant = function (parent, child) {
    let node = null
    if (typeof child.parentNode !== 'undefined') {
      node = child.parentNode
    }
    while (node !== null) {
      if (node === parent) {
        return true
      }
      node = node.parentNode
    }
    return false
  }

  WMEURMPT.restackUR = function () {
    WMEURMPT.logDebug('restackUR - stackedURList', WMEURMPT.stackedURList)
    if (WMEURMPT.stackedURList.length === 0) {
      return
    }
    for (let i = 0; i < WMEURMPT.stackedURList.length; i++) {
      const id = parseInt(WMEURMPT.stackedURList[i].id)
      const URAtt = WMEURMPT.wazeModel.mapUpdateRequests.objects[id].attributes
      URAtt.geometry.x = WMEURMPT.stackedURList[i].oriX
      URAtt.geometry.y = WMEURMPT.stackedURList[i].oriY
      if (URAtt.geometry.oriX !== 'undefined') {
        delete URAtt.geometry.oriX
      }
      if (URAtt.geometry.oriY !== 'undefined') {
        delete URAtt.geometry.oriY
      }
    }
    WMEURMPT.stackedURList = []
  }

  WMEURMPT.bootstrapURT = function () {
    window.setTimeout(WMEURMPT.initialize, 500)
  }
  WMEURMPT.setupPolicies = function () {
    if (typeof trustedTypes !== 'undefined') {
      WMEURMPT.policySafeHTML = trustedTypes.createPolicy('policySafeHTML', {
        createHTML: (innerText) => innerText
      })
      WMEURMPT.policySanitizeHTML = trustedTypes.createPolicy('policySanitizeHTML', {
        createHTML: (innerText) => innerText.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;').replace(/'/g, '&#039;')
      })
    }
  }
  WMEURMPT.initialize = function () {
    WMEURMPT.log('init')
    WMEURMPT.initializeWazeObjects()
    WMEURMPT.log('init done')
  }
  WMEURMPT.initializeElements = function () {
    const userInfo = WMEURMPT.getId('user-info')
    if (userInfo == null) {
      window.setTimeout(WMEURMPT.initializeElements, 500)
      return
    }
    const navTabs = userInfo.getElementsByTagName('ul')
    if (navTabs.length === 0) {
      window.setTimeout(WMEURMPT.initializeElements, 500)
      return
    }
    if (typeof navTabs[0] === 'undefined') {
      window.setTimeout(WMEURMPT.initializeElements, 500)
      return
    }
    const tabContents = userInfo.getElementsByTagName('div')
    if (tabContents.length === 0) {
      window.setTimeout(WMEURMPT.initializeElements, 500)
      return
    }
    if (typeof tabContents[0] === 'undefined') {
      window.setTimeout(WMEURMPT.initializeElements, 500)
      return
    }
    WMEURMPT.setupPolicies()
    WMEURMPT.load()
    W.prefs.on('change:isImperial', function () {
      WMEURMPT.unregisterEvents()
    })
  }

  WMEURMPT.waitForObject = function (varName, shortcutName) {
    let obj = null
    // eslint-disable-next-line no-eval
    obj = eval('typeof ' + varName)
    if (obj === 'undefined') {
      WMEURMPT.log(varName + ' KO')
      window.setTimeout(WMEURMPT.waitForObject.caller, 1000)
      return false
    }

    WMEURMPT.logDebug(varName + ' OK')
    if (shortcutName != null) {
      // eslint-disable-next-line no-eval
      eval('WMEURMPT.' + shortcutName + '=' + varName)
    }
    return true
  }

  WMEURMPT.initializeWazeObjects = function () {
    const objectToCheck = [
      { o: 'W.map', s: 'wazeMap' },
      { o: 'W.model', s: 'wazeModel' },
      { o: 'W.loginManager', s: 'loginManager' },
      { o: 'W.controller', s: 'wazeController' },
      { o: 'W.Config.api_base', s: 'wazeConfigApiBase' },
      { o: 'W.Config.paths.features', s: 'wazeConfigApiFeatures' },
      { o: 'W.Config.paths.updateRequestSessions', s: 'wazeConfigApiUpdateRequestSessions' },
      { o: 'OL', s: 'OpenLayers' },
      { o: 'W.loginManager.user', s: 'me' },
      { o: 'W.loginManager.user.attributes.rank', s: 'ul' },
      { o: 'W.loginManager.user.attributes.isAreaManager', s: 'uam' },
      { o: 'W.problemsController', s: 'wazePC' },
      { o: 'W.userscripts', s: 'wazeUS' }
    ]
    for (let i = 0; i < objectToCheck.length; i++) {
      const path = objectToCheck[i].o.split('.')
      let object = window
      for (let j = 0; j < path.length; j++) {
        object = object[path[j]]
        if (typeof object === 'undefined' || object == null) {
          window.setTimeout(WMEURMPT.initializeWazeObjects, 1000)
          return
        } else {
          WMEURMPT[objectToCheck[i].s] = object
        }
      }
    }
    WMEURMPT.ul = (WMEURMPT.ul + 1) * 2
    WMEURMPT.initializeElements()
  }

  WMEURMPT.registerEvents = function () {
    WMEURMPT.wazeMap.olMap.events.register('moveend', null, WMEURMPT.mapMoveEnd)
    WMEURMPT.wazeMap.olMap.events.register('zoomend', null, WMEURMPT.mapZoomEnd)
    WMEURMPT.wazeModel.events.register('mergeend', null, WMEURMPT.setupListener)
    WMEURMPT.wazeController.events.register('savestart', null, WMEURMPT.saveStarted)
    WMEURMPT.wazeController.events.register('saveend', null, WMEURMPT.saveEnded)
    WMEURMPT.wazeModel.mapUpdateRequests.on('objectschanged', WMEURMPT.newDataAvailableStarts)
    WMEURMPT.wazeModel.mapUpdateRequests.on('objectsadded', WMEURMPT.newDataAvailableStarts)
    WMEURMPT.wazeModel.mapUpdateRequests.on('objectsremoved', WMEURMPT.newDataAvailableStarts)

    WMEURMPT.wazeModel.mapProblems.on('objectschanged', WMEURMPT.newDataAvailableStarts)
    WMEURMPT.wazeModel.mapProblems.on('objectsadded', WMEURMPT.newDataAvailableStarts)
    WMEURMPT.wazeModel.mapProblems.on('objectsremoved', WMEURMPT.newDataAvailableStarts)

    WMEURMPT.wazeModel.mapComments.on('objectschanged', WMEURMPT.newDataAvailableStarts)
    WMEURMPT.wazeModel.mapComments.on('objectsadded', WMEURMPT.newDataAvailableStarts)
    WMEURMPT.wazeModel.mapComments.on('objectsremoved', WMEURMPT.newDataAvailableStarts)
    WMEURMPT.wazeModel.venues.on('objectschanged', WMEURMPT.newDataAvailableStarts)
    WMEURMPT.wazeModel.venues.on('objectsadded', WMEURMPT.newDataAvailableStarts)
    WMEURMPT.wazeModel.venues.on('objectsremoved', WMEURMPT.newDataAvailableStarts)
    WMEURMPT.wazeModel.actionManager.events.register('afteraction', null, WMEURMPT.newActionAdded)
    WMEURMPT.wazeModel.actionManager.events.register('afterundoaction', null, WMEURMPT.newActionAdded)
    WMEURMPT.wazeModel.actionManager.events.register('afterclearaction', null, WMEURMPT.newActionAdded)
    W.app.on('problems:shown', WMEURMPT.onProblemsShown)
    window.setTimeout(WMEURMPT.setupListener, 500)
  }

  WMEURMPT.unregisterEvents = function () {
    WMEURMPT.wazeMap.olMap.events.unregister('moveend', null, WMEURMPT.mapMoveEnd)
    WMEURMPT.wazeMap.olMap.events.unregister('zoomend', null, WMEURMPT.mapZoomEnd)
    WMEURMPT.wazeModel.events.unregister('mergeend', null, WMEURMPT.setupListener)
    WMEURMPT.wazeController.events.unregister('savestart', null, WMEURMPT.saveStarted)
    WMEURMPT.wazeController.events.unregister('saveend', null, WMEURMPT.saveEnded)
    WMEURMPT.wazeModel.mapUpdateRequests.off('objectschanged', WMEURMPT.newDataAvailableStarts)
    WMEURMPT.wazeModel.mapUpdateRequests.off('objectsadded', WMEURMPT.newDataAvailableStarts)
    WMEURMPT.wazeModel.mapUpdateRequests.off('objectsremoved', WMEURMPT.newDataAvailableStarts)
    WMEURMPT.wazeModel.mapProblems.off('objectschanged', WMEURMPT.newDataAvailableStarts)
    WMEURMPT.wazeModel.mapProblems.off('objectsadded', WMEURMPT.newDataAvailableStarts)
    WMEURMPT.wazeModel.mapProblems.off('objectsremoved', WMEURMPT.newDataAvailableStarts)
    WMEURMPT.wazeModel.mapComments.off('objectschanged', WMEURMPT.newDataAvailableStarts)
    WMEURMPT.wazeModel.mapComments.off('objectsadded', WMEURMPT.newDataAvailableStarts)
    WMEURMPT.wazeModel.mapComments.off('objectsremoved', WMEURMPT.newDataAvailableStarts)
    WMEURMPT.wazeModel.venues.off('objectschanged', WMEURMPT.newDataAvailableStarts)
    WMEURMPT.wazeModel.venues.off('objectsadded', WMEURMPT.newDataAvailableStarts)
    WMEURMPT.wazeModel.venues.off('objectsremoved', WMEURMPT.newDataAvailableStarts)
    WMEURMPT.wazeModel.actionManager.events.unregister('afteraction', null, WMEURMPT.newActionAdded)
    WMEURMPT.wazeModel.actionManager.events.unregister('afterundoaction', null, WMEURMPT.newActionAdded)
    WMEURMPT.wazeModel.actionManager.events.unregister('afterclearaction', null, WMEURMPT.newActionAdded)
    W.app.off('problems:shown', WMEURMPT.onProblemsShown)
  }

  WMEURMPT.initManagedArea = function () {
    const userAreas = WMEURMPT.me.attributes.areas
    for (let a = 0; a < userAreas.length; a++) {
      if (userAreas[a].type === 'drive') {
        const tmpArea = W.userscripts.toOLGeometry(userAreas[a].geometry)
        for (let c = 0; c < tmpArea.components.length; c++) {
          tmpArea.components[c].calculateBounds()
          WMEURMPT.driveArea.push(tmpArea.components[c])
        }
      }
      if (userAreas[a].type === 'managed') {
        const tmpArea = W.userscripts.toOLGeometry(userAreas[a].geometry)
        for (let c = 0; c < tmpArea.components.length; c++) {
          tmpArea.components[c].calculateBounds()
          WMEURMPT.managedAreas.push(tmpArea.components[c])
        }
      }
    }
    WMEURMPT.logDebug('WMEURMPT.driveArea', WMEURMPT.driveArea)
    WMEURMPT.logDebug('WMEURMPT.managedAreas', WMEURMPT.managedAreas)
  }

  WMEURMPT.initCountryList = function () {
    const countryList = new WMEURMPT.URT_AREA()
    countryList.category = 'country'
    countryList.getCategoryElementsFromServer(WMEURMPT.newCountryListAvailable)
  }

  WMEURMPT.newCountryListAvailable = function (countryList) {
    const countryListSelect = WMEURMPT.getId('urmpt-countryList')
    let optionList = ''
    for (let c = 0; c < countryList.length; c++) {
      optionList += '<option value="' + countryList[c].name.replace(/ /g, '_') + '">' + countryList[c].name + '</option>'
      optionList += WMEURMPT.rescurseSubset(countryList[c], '')
    }
    countryListSelect.innerHTML += WMEURMPT.convertHtml(optionList)
  }

  WMEURMPT.rescurseSubset = function (subset, parentPath) {
    let optionList = ''
    if (typeof subset.set !== 'undefined') {
      for (let i = 0; i < subset.set.length; i++) {
        const fullPath = parentPath + subset.name + '->' + subset.set[i].name
        optionList += '<option value="' + fullPath.replace(/ /g, '_') + '">' + fullPath + '</option>'
        optionList += WMEURMPT.rescurseSubset(subset.set[i], (parentPath === '' ? '' : parentPath + '->') + subset.name + '->')
      }
    } else {
      for (let i = 0; i < subset.subset.length; i++) {
        optionList += WMEURMPT.rescurseSubset(subset.subset[i], (parentPath === '' ? '' : parentPath + '->') + subset.name + '->')
      }
    }
    return optionList
  }

  WMEURMPT.errorOnCountryServer = function () {
    const countryListSelect = WMEURMPT.getId('urmpt-countryList')
    const errorMessage = WMEURMPT.createElement('span')
    errorMessage.style.color = '#FF0000'
    errorMessage.innerHTML = WMEURMPT.convertHtml('Error while getting list of countries<br/>You can try later by reloading WME<br/>Sorry for the inconvenience.')
    countryListSelect.parentNode.parentNode.replaceChild(errorMessage, countryListSelect.parentNode)
  }

  WMEURMPT.wazeMapAreaToOLPolygons = function (geometry) {
    const polygons = []
    if (geometry.type === 'Polygon') {
      polygons.push(WMEURMPT.lonlatArrayToxyOpenLayersPolygons(geometry.coordinates))
      polygons[polygons.length - 1].calculateBounds()
    }
    if (geometry.type === 'MultiPolygon') {
      for (let p = 0; p < geometry.coordinates.length; p++) {
        polygons.push(WMEURMPT.lonlatArrayToxyOpenLayersPolygons(geometry.coordinates[p]))
        polygons[polygons.length - 1].calculateBounds()
      }
    }
    return polygons
  }

  WMEURMPT.bintreeGeometry = function (poly) {
    let pointList = null
    if (poly.CLASS_NAME === 'OpenLayers.Geometry.LinearRing') {
      pointList = poly.components
    } else {
      pointList = poly.components[0].components
    }
    if (pointList.length <= 15) {
      return
    }
    let split = 'x'
    let notSplit = 'y'
    let splitValue = (poly.bounds.right + poly.bounds.left) / 2.0
    if (poly.bounds.right - poly.bounds.left < poly.bounds.top - poly.bounds.bottom) {
      split = 'y'
      notSplit = 'x'
      splitValue = (poly.bounds.top + poly.bounds.bottom) / 2.0
    }
    const intersection = []
    for (let p = 0; p < pointList.length - 1; p++) {
      const point = pointList[p]
      const next = pointList[p + 1]
      if ((point[split] <= splitValue && next[split] > splitValue) || (point[split] > splitValue && next[split] <= splitValue)) {
        intersection.push(p)
      }
    }
    for (let j = 0; j < intersection.length; j++) {
      const olPoint = new OpenLayers.Geometry.Point(0, 0)
      const p1 = pointList[intersection[j]]
      const p2 = pointList[intersection[j] + 1]
      olPoint[split] = splitValue
      if (p2[split] - p1[split] === 0) {
        olPoint[notSplit] = p1[notSplit]
      } else {
        const ratio = (splitValue - p1[split]) / (p2[split] - p1[split])
        olPoint[notSplit] = ratio * (p2[notSplit] - p1[notSplit]) + p1[notSplit]
      }
      intersection[j] = { index: intersection[j], point: olPoint }
    }
    intersection.sort(function (a, b) {
      return a.point[notSplit] > b.point[notSplit]
    })

    const bintree = [[], []]
    let currentL = -1
    let currentR = -1
    let intersectionIndex = -1
    let found = false
    const intersectionIndices = intersection.map(function (e) {
      return e.index
    })

    for (let p = 0; p < pointList.length - 1; p++) {
      const i = (p + intersection[0].index) % (pointList.length - 1)
      if (pointList[i][split] <= splitValue) {
        if (currentL === -1) {
          bintree[0].push({ i: [], c: false })
          currentL = 0
        }
        bintree[0][currentL].i.push(i)
        intersectionIndex = intersectionIndices.indexOf(i)
        if (intersectionIndex !== -1) {
          bintree[0][currentL].i.push(intersectionIndex * -1 - 1)
          found = false
          for (let b = 0; b < bintree[1].length; b++) {
            if ((intersectionIndex % 2 === 0 && (bintree[1][b].i[bintree[1][b].i.length - 1] + 1) * -1 === intersectionIndex + 1) || (intersectionIndex % 2 === 1 && (bintree[1][b].i[bintree[1][b].i.length - 1] + 1) * -1 === intersectionIndex - 1)) {
              found = true
              currentR = b
              break
            }
          }
          if (!found) {
            bintree[1].push({ i: [], c: false })
            currentR = bintree[1].length - 1
          }
          bintree[1][currentR].i.push(intersectionIndex * -1 - 1)
        }
      } else {
        if (currentR === -1) {
          bintree[1].push({ i: [], c: false })
          currentR = 0
        }
        bintree[1][currentR].i.push(i)
        intersectionIndex = intersectionIndices.indexOf(i)
        if (intersectionIndex !== -1) {
          bintree[1][currentR].i.push(intersectionIndex * -1 - 1)
          found = false
          for (let b = 0; b < bintree[0].length; b++) {
            if ((intersectionIndex % 2 === 0 && (bintree[0][b].i[bintree[0][b].i.length - 1] + 1) * -1 === intersectionIndex + 1) || (intersectionIndex % 2 === 1 && (bintree[0][b].i[bintree[0][b].i.length - 1] + 1) * -1 === intersectionIndex - 1)) {
              found = true
              currentL = b
              break
            }
          }
          if (!found) {
            bintree[0].push({ i: [], c: false })
            currentL = bintree[0].length - 1
          }
          bintree[0][currentL].i.push(intersectionIndex * -1 - 1)
        }
      }
    }
    const bintree2 = [[], []]
    poly.bintree = { left: null, right: null }
    for (let t = 0; t < 2; t++) {
      const olPolyList = []
      for (let i = 0; i < bintree[t].length; i++) {
        bintree2[t].push([])
        for (let j = 0; j < bintree[t][i].i.length; j++) {
          if (bintree[t][i].i[j] < 0) {
            intersectionIndex = (bintree[t][i].i[j] + 1) * -1
            const olPoint = intersection[intersectionIndex].point
            bintree2[t][i].push(olPoint)
          } else {
            bintree2[t][i].push(pointList[bintree[t][i].i[j]])
          }
        }
        bintree2[t][i].push(bintree2[t][i][0])
        olPolyList.push(new OpenLayers.Geometry.Polygon(new OpenLayers.Geometry.LinearRing(bintree2[t][i])))
        olPolyList[olPolyList.length - 1].calculateBounds()
        WMEURMPT.bintreeGeometry(olPolyList[olPolyList.length - 1])
      }
      if (t === 0) {
        poly.bintree.left = new OpenLayers.Geometry.MultiPolygon(olPolyList)
      } else {
        poly.bintree.right = new OpenLayers.Geometry.MultiPolygon(olPolyList)
      }
    }
    poly.bintreeContainsPoint = function (point) {
      if (point.x < this.bounds.left || point.x > this.bounds.right || point.y < this.bounds.bottom || point.y > this.bounds.top) {
        return false
      }
      if (Object.prototype.hasOwnProperty.call(this, 'bintree') === true) {
        for (let i = 0; i < this.bintree.left.components.length; i++) {
          if (Object.prototype.hasOwnProperty.call(this.bintree.left.components[i], 'bintree') === true) {
            if (this.bintree.left.components[i].bintreeContainsPoint(point) === true) {
              return true
            }
          } else if (this.bintree.left.components[i].containsPoint(point) === true) {
            return true
          }
        }
        for (let i = 0; i < this.bintree.right.components.length; i++) {
          if (Object.prototype.hasOwnProperty.call(this.bintree.right.components[i], 'bintree') === true) {
            if (this.bintree.right.components[i].bintreeContainsPoint(point) === true) {
              return true
            }
          } else if (this.bintree.right.components[i].containsPoint(point) === true) {
            return true
          }
        }
        return false
      }
      return this.containsPoint(point)
    }
  }

  WMEURMPT.lonlatArrayToxyOpenLayersPolygons = function (lontalArray) {
    const olPolygons = []
    for (let p = 0; p < lontalArray.length; p++) {
      const olPoints = []
      for (let pt = 0; pt < lontalArray[p].length - 1; pt++) {
        const xy = OpenLayers.Layer.SphericalMercator.forwardMercator(lontalArray[p][pt][0], lontalArray[p][pt][1])
        olPoints.push(new OpenLayers.Geometry.Point(xy.lon, xy.lat))
      }
      olPolygons.push(new OpenLayers.Geometry.LinearRing(olPoints))
    }
    if (olPolygons.length >= 1) {
      const olLinearRing = olPolygons[0]
      return new OpenLayers.Geometry.Polygon([olLinearRing])
    }
    return null
  }

  WMEURMPT.isInAreas = function (lonlat) {
    for (let c = 0; c < WMEURMPT.areaList.country.length; c++) {
      if (WMEURMPT.areaList.country[c].isInside(lonlat)) {
        return true
      }
    }
    for (let c = 0; c < WMEURMPT.areaList.custom.length; c++) {
      if (WMEURMPT.areaList.custom[c].isInside(lonlat)) {
        return true
      }
    }
    return false
  }

  WMEURMPT.inScreenUpdatableArea = function (xy) {
    if (Object.prototype.hasOwnProperty.call(WMEURMPT.wazeModel.userAreas.objects, 'managed')) {
      if (WMEURMPT.wazeModel.userAreas.objects.managed.attributes.geometry.containsPoint(xy)) {
        return true
      }
    }
    if (Object.prototype.hasOwnProperty.call(WMEURMPT.wazeModel.userAreas.objects, 'drives')) {
      if (WMEURMPT.wazeModel.userAreas.objects.drives.attributes.geometry.containsPoint(xy)) {
        return true
      }
    }
    return false
  }

  WMEURMPT.isInsideDriveArea = function (lon, lat) {
    const lonlat = OpenLayers.Layer.SphericalMercator.forwardMercator(lon, lat)
    const xy = new OpenLayers.Geometry.Point(lonlat.lon, lonlat.lat)
    for (let a = 0; a < WMEURMPT.driveArea.length; a++) {
      if (xy.x >= WMEURMPT.driveArea[a].bounds.left && xy.x <= WMEURMPT.driveArea[a].bounds.right && xy.y >= WMEURMPT.driveArea[a].bounds.bottom && xy.y <= WMEURMPT.driveArea[a].bounds.top && WMEURMPT.driveArea[a].containsPoint(xy)) {
        return true
      }
    }
    return false
  }

  WMEURMPT.isInsideManagedArea = function (lon, lat) {
    const lonlat = OpenLayers.Layer.SphericalMercator.forwardMercator(lon, lat)
    const xy = new OpenLayers.Geometry.Point(lonlat.lon, lonlat.lat)
    for (let a = 0; a < WMEURMPT.managedAreas.length; a++) {
      if (xy.x >= WMEURMPT.managedAreas[a].bounds.left && xy.x <= WMEURMPT.managedAreas[a].bounds.right && xy.y >= WMEURMPT.managedAreas[a].bounds.bottom && xy.y <= WMEURMPT.managedAreas[a].bounds.top && WMEURMPT.managedAreas[a].containsPoint(xy)) {
        return true
      }
    }
    return false
  }

  WMEURMPT.getSelectedProblem = function () {
    try {
      const mpLayer = WMEURMPT.wazeMap.getLayerByName('mapProblems')
      if (typeof mpLayer !== 'undefined') {
        for (const m of mpLayer.features) {
          if (m.attributes.wazeFeature.isSelected) {
            return m.attributes.wazeFeature.id
          }
        }
      }
    } catch (e) {
      WMEURMPT.log('error while getting selected problem: ', e)
    }
    return null
  }

  WMEURMPT.getSelectedUR = function () {
    try {
      const urLayer = WMEURMPT.wazeMap.getLayerByName('update_requests')
      for (const m of urLayer.features) {
        if (m.attributes.wazeFeature.isSelected) {
          if (typeof m.attributes.wazeFeature.id !== 'undefined') {
            return m.attributes.wazeFeature.id
          }
          return null
        }
      }
    } catch (e) {
      WMEURMPT.log('error while getting selected UR: ', e)
    }
    return null
  }

  WMEURMPT.getSelectedMC = function () {
    let m = null
    try {
      m = W.selectionManager.getSelectedDataModelObjects()
    } catch {
      return null
    }
    let returnId = null
    if ((Array.isArray(m) === false) || ((Array.isArray(m)) && (m.length !== 1))) {
      return null
    }

    if ((typeof m[0].type !== 'undefined') && (m[0].type === 'mapComment') && ((returnId = m[0].getID()) !== null)) {
      return returnId
    }
    return null
  }

  WMEURMPT.getSelectedPUR = function () {
    try {
      const placeUpdates = WMEURMPT.wazeMap.getLayerByName('place_updates')

      for (const m of placeUpdates.features) {
        if (m.attributes.wazeFeature.isSelected) {
          if (typeof m.attributes.wazeFeature.id !== 'undefined') {
            return m.attributes.wazeFeature.id
          }
          return null
        }
      }
    } catch (e) {
      WMEURMPT.log('error while getting selected PUR: ', e)
    }
    return null
  }

  WMEURMPT.updateRequestSessions = function () {
    const ids = []
    let xhr3Object = null
    for (const i in WMEURMPT.wazeModel.mapUpdateRequests.objects) {
      if (WMEURMPT.wazeModel.updateRequestSessions.objects[i] == null) {
        ids.push(i)
      }
    }
    if (ids.length !== 0) {
      const url = 'https://' + document.location.host + WMEURMPT.wazeConfigApiUpdateRequestSessions + '?ids=' + ids.join(',')
      if (XMLHttpRequest) {
        xhr3Object = new XMLHttpRequest()
      } else if (ActiveXObject) {
        xhr3Object = new ActiveXObject('Microsoft.XMLHTTP')
      }
      let URcomments = null
      xhr3Object.open('GET', url, false)
      xhr3Object.ontimeout = function () {
        URcomments = null
      }
      xhr3Object.onerror = function () {
        URcomments = null
      }
      xhr3Object.onreadystatechange = function () {
        if (xhr3Object.readyState === 4) {
          const r = xhr3Object.responseText
          try {
            URcomments = JSON.parse(r)
          } catch (e) {
            WMEURMPT.log("Error: can't read server response: ", e)
            WMEURMPT.log('Response from server: ', r)
            WMEURMPT.log('Query: ', url)
            URcomments = null
          }
        } else {
          URcomments = null
        }
      }
      xhr3Object.send(null)
      WMEURMPT.logDebug('UR comments: ', URcomments)
      if (URcomments != null) {
        for (let j = 0; j < URcomments.updateRequestSessions.objects.length; j++) {
          const urId = URcomments.updateRequestSessions.objects[j].id
          const ur = WMEURMPT.getURFromId(urId)
          if (ur != null) {
            ur.data.session = URcomments.updateRequestSessions.objects[j]
            ur.data.session.users = URcomments.users
            for (let c = 0; c < ur.data.session.comments.length; c++) {
              const userID = ur.data.session.comments[c].userID
              let userName = 'Unknown'
              if (userID === WMEURMPT.me.getID()) {
                userName = WMEURMPT.me.getUsername()
                if (c === ur.data.session.comments.length - 1) {
                  ur.lastVisitCommentsCount = ur.data.session.comments.length
                }
              }
              if (userID === -1) {
                userName = 'Reporter'
              } else {
                for (let u = 0; u < ur.data.session.users.objects.length; u++) {
                  if (ur.data.session.users.objects[u].id === userID) {
                    userName = ur.data.session.users.objects[u].userName
                    break
                  }
                }
              }
              ur.data.session.comments[c].userName = userName
            }
          }
        }
      }
    }
  }

  WMEURMPT.settingsSetURDescriptionWidth = function () {
    WMEURMPT.URDescriptionMaxLength = this.value
    WMEURMPT.saveOptions()
  }

  WMEURMPT.settingsSetMPDescriptionWidth = function () {
    WMEURMPT.MPDescriptionMaxLength = this.value
    WMEURMPT.saveOptions()
  }

  WMEURMPT.settingsSetMCSubjectWidth = function () {
    WMEURMPT.MCSubjectMaxLength = this.value
    WMEURMPT.saveOptions()
  }

  WMEURMPT.settingsSetMCBodyWidth = function () {
    WMEURMPT.MCBodyMaxLength = this.value
    WMEURMPT.saveOptions()
  }

  WMEURMPT.settingsSetURTagList = function () {
    WMEURMPT.taggedURList = this.value.split(';')
    WMEURMPT.saveOptions()
  }

  WMEURMPT.settingsSetPURCategoriesWidth = function () {
    WMEURMPT.PURCategoriesMaxLength = this.value
    WMEURMPT.saveOptions()
  }

  WMEURMPT.settingsSetPURNameWidth = function () {
    WMEURMPT.PURNameMaxLength = this.value
    WMEURMPT.saveOptions()
  }

  WMEURMPT.isURFiltered = function (ur) {
    let invert = function (a) {
      return a
    }
    if (WMEURMPT.urtInvertFilter === true) {
      invert = function (a) {
        return !a
      }
    }
    return invert(WMEURMPT.isURFiltered2(ur))
  }

  WMEURMPT.isURFiltered2 = function (ur) {
    const userId = WMEURMPT.loginManager.user.getID()
    let found = false
    let inside = false
    let filterArea = []
    if (WMEURMPT.currentURFilter & WMEURMPT.URFilterList.hideClosed && ur.data.open === false) {
      return true
    }
    if (ur.data.open === false && WMEURMPT.ul < WMEURMPT.rl4cp) {
      return true
    }
    if (WMEURMPT.currentURFilter & WMEURMPT.URFilterList.hideLastCommentFromEditor) {
      if (ur.data.session.comments.length === 0 || ur.data.session.comments[ur.data.session.comments.length - 1].userID !== -1) {
        return true
      }
    }
    if (WMEURMPT.currentURFilter & WMEURMPT.URFilterList.hideNoNewComment) {
      if (ur.data.session.comments.length <= ur.lastVisitCommentsCount) {
        return true
      }
    }
    if (WMEURMPT.currentURFilter & WMEURMPT.URFilterList.hideWithCommentCount && ur.data.session.comments.length > WMEURMPT.currentURCommentsCount) {
      return true
    }
    if (WMEURMPT.currentURFilter & WMEURMPT.URFilterList.hideOutOfMyDriveArea) {
      if (!WMEURMPT.isInsideDriveArea(ur.lonlat.lon, ur.lonlat.lat)) {
        return true
      }
    }
    if (WMEURMPT.currentURFilter & WMEURMPT.URFilterList.hideOutOfMyManagedArea && WMEURMPT.uam) {
      if (!WMEURMPT.isInsideManagedArea(ur.lonlat.lon, ur.lonlat.lat)) {
        return true
      }
    }
    if (WMEURMPT.currentURFilter & WMEURMPT.URFilterList.hideVisited && ur.alreadyVisited) {
      return true
    }
    if (WMEURMPT.currentURFilter & WMEURMPT.URFilterList.hideBlacklisted && ur.blackListed) {
      return true
    }
    if (WMEURMPT.currentURFilter & WMEURMPT.URFilterList.hideWhitelisted && !ur.blackListed) {
      return true
    }
    if (WMEURMPT.currentURFilter & WMEURMPT.URFilterList.hideGE && ur.data.type === 10) {
      return true
    }
    if (WMEURMPT.currentURFilter & WMEURMPT.URFilterList.hideType && ur.data.type !== WMEURMPT.currentUROnlyType) {
      return true
    }
    if (WMEURMPT.currentURFilter & WMEURMPT.URFilterList.hideTagged) {
      if (ur.data.description != null) {
        for (let i = 0; i < WMEURMPT.taggedURList.length; i++) {
          if (ur.data.description.toLowerCase().indexOf(WMEURMPT.taggedURList[i].toLowerCase()) !== -1) {
            return true
          }
        }
      }
      for (let c = 0; c < ur.data.session.comments.length; c++) {
        for (let i = 0; i < WMEURMPT.taggedURList.length; i++) {
          if (ur.data.session.comments[c].text.toLowerCase().indexOf(WMEURMPT.taggedURList[i].toLowerCase()) !== -1) {
            return true
          }
        }
      }
    }
    if (WMEURMPT.currentURFilter & WMEURMPT.URFilterList.hideWithoutCommentFromMe) {
      found = false
      for (let c = 0; c < ur.data.session.comments.length; c++) {
        if (ur.data.session.comments[c].userID === userId) {
          found = true
          break
        }
      }
      if (!found) {
        return true
      }
    }
    if (WMEURMPT.currentURFilter & WMEURMPT.URFilterList.hideNotKW) {
      found = false
      if (ur.data.description !== null && ur.data.description.toLowerCase().indexOf(WMEURMPT.currentURKeyWord.toLowerCase()) !== -1) {
        found = true
      }
      if (!found && ur.data.open === false && Object.prototype.hasOwnProperty.call(ur.data, 'resolvedByName') && ur.data.resolvedByName.toLowerCase() === WMEURMPT.currentURKeyWord.toLowerCase()) {
        found = true
      }
      if (!found && ur.data.session.comments.length > 0) {
        for (let i = 0; i < ur.data.session.comments.length; i++) {
          if (Object.prototype.hasOwnProperty.call(ur.data.session.comments[i], 'userName') === false) {
            continue
          }
          if (typeof ur.data.session.comments[i].userName !== 'string') {
            continue
          }
          if (ur.data.session.comments[i].userName.toLowerCase() === WMEURMPT.currentURKeyWord.toLowerCase()) {
            found = true
            break
          } else if (ur.data.session.comments[i].text.toLowerCase().indexOf(WMEURMPT.currentURKeyWord.toLowerCase()) !== -1) {
            found = true
            break
          }
        }
      }
      if (!found) {
        return true
      }
    }
    if (WMEURMPT.currentURFilter & WMEURMPT.URFilterList.hideArea) {
      const xy = new OpenLayers.Geometry.Point(ur.lonlat.lon, ur.lonlat.lat)
      for (let i = 0; i < WMEURMPT.areaList.custom.length; i++) {
        if (WMEURMPT.areaList.custom[i].name === WMEURMPT.currentUROnlyArea) {
          inside = false
          filterArea = WMEURMPT.areaList.custom[i].geometryOL.geometry.components
          for (let a = 0; a < filterArea.length; a++) {
            if (Object.prototype.hasOwnProperty.call(filterArea[a], 'bintreeContainsPoint') === false) {
              if (xy.x >= filterArea[a].bounds.left && xy.x <= filterArea[a].bounds.right && xy.y >= filterArea[a].bounds.bottom && xy.y <= filterArea[a].bounds.top && filterArea[a].containsPoint(xy)) {
                inside = true
                break
              }
            } else {
              if (filterArea[a].bintreeContainsPoint(xy)) {
                inside = true
                break
              }
            }
          }
          if (inside === false) {
            return true
          }
        }
      }
      for (let i = 0; i < WMEURMPT.areaList.country.length; i++) {
        if (WMEURMPT.areaList.country[i].name === WMEURMPT.currentUROnlyArea) {
          inside = false
          filterArea = WMEURMPT.areaList.country[i].geometryOL.geometry.components
          for (let a = 0; a < filterArea.length; a++) {
            if (Object.prototype.hasOwnProperty.call(filterArea[a], 'bintreeContainsPoint') === false) {
              if (xy.x >= filterArea[a].bounds.left && xy.x <= filterArea[a].bounds.right && xy.y >= filterArea[a].bounds.bottom && xy.y <= filterArea[a].bounds.top && filterArea[a].containsPoint(xy)) {
                inside = true
                break
              }
            } else {
              if (filterArea[a].bintreeContainsPoint(xy)) {
                inside = true
                break
              }
            }
          }
          if (inside === false) {
            return true
          }
        }
      }
    }
    return false
  }
  WMEURMPT.isMPFiltered = function (mp) {
    let inside = false
    let filterArea = []
    if (WMEURMPT.currentMPFilter & WMEURMPT.MPFilterList.hideClosed && mp.data.open === false) {
      return true
    }
    if (mp.data.open === false && WMEURMPT.ul < WMEURMPT.rl4cp) {
      return true
    }
    if (WMEURMPT.currentMPFilter & WMEURMPT.MPFilterList.hideOutOfMyDriveArea) {
      if (!WMEURMPT.isInsideDriveArea(mp.lonlat.lon, mp.lonlat.lat)) {
        return true
      }
    }
    if (WMEURMPT.currentMPFilter & WMEURMPT.MPFilterList.hideOutOfMyManagedArea && WMEURMPT.uam) {
      if (!WMEURMPT.isInsideManagedArea(mp.lonlat.lon, mp.lonlat.lat)) {
        return true
      }
    }
    if (WMEURMPT.currentMPFilter & WMEURMPT.MPFilterList.hideVisited && mp.alreadyVisited) {
      return true
    }
    if (WMEURMPT.currentMPFilter & WMEURMPT.MPFilterList.hideBlacklisted && mp.blackListed) {
      return true
    }
    if (WMEURMPT.currentMPFilter & WMEURMPT.MPFilterList.hideWhitelisted && !mp.blackListed) {
      return true
    }
    if (WMEURMPT.currentMPFilter & WMEURMPT.MPFilterList.hideType) {
      if (WMEURMPT.currentMPOnlyType === 0 && mp.type !== 'turnProblem') {
        return true
      }
      if (WMEURMPT.currentMPOnlyType !== 0 && mp.data.subType !== WMEURMPT.currentMPOnlyType) {
        return true
      }
    }
    if (WMEURMPT.currentMPFilter & WMEURMPT.MPFilterList.hideArea) {
      const xy = new OpenLayers.Geometry.Point(mp.lonlat.lon, mp.lonlat.lat)
      for (let i = 0; i < WMEURMPT.areaList.custom.length; i++) {
        if (WMEURMPT.areaList.custom[i].name === WMEURMPT.currentMPOnlyArea) {
          inside = false
          filterArea = WMEURMPT.areaList.custom[i].geometryOL.geometry.components
          for (let a = 0; a < filterArea.length; a++) {
            if (Object.prototype.hasOwnProperty.call(filterArea[a], 'bintreeContainsPoint') === false) {
              if (xy.x >= filterArea[a].bounds.left && xy.x <= filterArea[a].bounds.right && xy.y >= filterArea[a].bounds.bottom && xy.y <= filterArea[a].bounds.top && filterArea[a].containsPoint(xy)) {
                inside = true
                break
              }
            } else {
              if (filterArea[a].bintreeContainsPoint(xy)) {
                inside = true
                break
              }
            }
          }
          if (inside === false) {
            return true
          }
        }
      }
      for (let i = 0; i < WMEURMPT.areaList.country.length; i++) {
        if (WMEURMPT.areaList.country[i].name === WMEURMPT.currentMPOnlyArea) {
          inside = false
          filterArea = WMEURMPT.areaList.country[i].geometryOL.geometry.components
          for (let a = 0; a < filterArea.length; a++) {
            if (Object.prototype.hasOwnProperty.call(filterArea[a], 'bintreeContainsPoint') === false) {
              if (xy.x >= filterArea[a].bounds.left && xy.x <= filterArea[a].bounds.right && xy.y >= filterArea[a].bounds.bottom && xy.y <= filterArea[a].bounds.top && filterArea[a].containsPoint(xy)) {
                inside = true
                break
              }
            } else {
              if (filterArea[a].bintreeContainsPoint(xy)) {
                inside = true
                break
              }
            }
          }
          if (inside === false) {
            return true
          }
        }
      }
    }
    return false
  }
  WMEURMPT.isMCFiltered = function (mc) {
    let inside = false
    let filterArea = []
    if (WMEURMPT.currentMCFilter & WMEURMPT.MCFilterList.hideOutOfMyDriveArea) {
      if (!WMEURMPT.isInsideDriveArea(mc.lonlat.lon, mc.lonlat.lat)) {
        return true
      }
    }
    if (WMEURMPT.currentMCFilter & WMEURMPT.MCFilterList.hideOutOfMyManagedArea && WMEURMPT.uam) {
      if (!WMEURMPT.isInsideManagedArea(mc.lonlat.lon, mc.lonlat.lat)) {
        return true
      }
    }
    if (WMEURMPT.currentMCFilter & WMEURMPT.MCFilterList.hideVisited && mc.alreadyVisited) {
      return true
    }
    if (WMEURMPT.currentMCFilter & WMEURMPT.MCFilterList.hideBlacklisted && mc.blackListed) {
      return true
    }
    if (WMEURMPT.currentMCFilter & WMEURMPT.MCFilterList.hideWhitelisted && !mc.blackListed) {
      return true
    }
    if (WMEURMPT.currentMCFilter & WMEURMPT.MCFilterList.hideNotKW && (mc.data.subject != null && mc.data.subject.toLowerCase().indexOf(WMEURMPT.currentMCKeyWord.toLowerCase()) === -1) && (mc.data.body != null && mc.data.body.toLowerCase().indexOf(WMEURMPT.currentMCKeyWord.toLowerCase()) === -1)) {
      return true
    }
    if (WMEURMPT.currentMCFilter & WMEURMPT.MCFilterList.hideArea) {
      const xy = new OpenLayers.Geometry.Point(mc.lonlat.lon, mc.lonlat.lat)
      for (let i = 0; i < WMEURMPT.areaList.custom.length; i++) {
        if (WMEURMPT.areaList.custom[i].name === WMEURMPT.currentMCOnlyArea) {
          inside = false
          filterArea = WMEURMPT.areaList.custom[i].geometryOL.geometry.components
          for (let a = 0; a < filterArea.length; a++) {
            if (Object.prototype.hasOwnProperty.call(filterArea[a], 'bintreeContainsPoint') === false) {
              if (xy.x >= filterArea[a].bounds.left && xy.x <= filterArea[a].bounds.right && xy.y >= filterArea[a].bounds.bottom && xy.y <= filterArea[a].bounds.top && filterArea[a].containsPoint(xy)) {
                inside = true
                break
              }
            } else {
              if (filterArea[a].bintreeContainsPoint(xy)) {
                inside = true
                break
              }
            }
          }
          if (inside === false) {
            return true
          }
        }
      }
      for (let i = 0; i < WMEURMPT.areaList.country.length; i++) {
        if (WMEURMPT.areaList.country[i].name === WMEURMPT.currentMCOnlyArea) {
          inside = false
          filterArea = WMEURMPT.areaList.country[i].geometryOL.geometry.components
          for (let a = 0; a < filterArea.length; a++) {
            if (Object.prototype.hasOwnProperty.call(filterArea[a], 'bintreeContainsPoint') === false) {
              if (xy.x >= filterArea[a].bounds.left && xy.x <= filterArea[a].bounds.right && xy.y >= filterArea[a].bounds.bottom && xy.y <= filterArea[a].bounds.top && filterArea[a].containsPoint(xy)) {
                inside = true
                break
              }
            } else {
              if (filterArea[a].bintreeContainsPoint(xy)) {
                inside = true
                break
              }
            }
          }
          if (inside === false) {
            return true
          }
        }
      }
    }
    return false
  }
  WMEURMPT.isPURFiltered = function (pur) {
    let invert = function (a) {
      return a
    }
    if (WMEURMPT.purInvertFilter === true) {
      invert = function (a) {
        return !a
      }
    }
    return invert(WMEURMPT.isPURFiltered2(pur))
  }

  WMEURMPT.isPURFiltered2 = function (pur) {
    let inside = false
    let filterArea = []
    if (WMEURMPT.currentPURFilter & WMEURMPT.PURFilterList.hideOutOfMyDriveArea) {
      if (!WMEURMPT.isInsideDriveArea(pur.lonlat.lon, pur.lonlat.lat)) {
        return true
      }
    }
    if (WMEURMPT.currentPURFilter & WMEURMPT.PURFilterList.hideOutOfMyManagedArea && WMEURMPT.uam) {
      if (!WMEURMPT.isInsideManagedArea(pur.lonlat.lon, pur.lonlat.lat)) {
        return true
      }
    }
    if (WMEURMPT.currentPURFilter & WMEURMPT.PURFilterList.hideVisited && pur.alreadyVisited) {
      return true
    }
    if (WMEURMPT.currentPURFilter & WMEURMPT.PURFilterList.hideBlacklisted && pur.blackListed) {
      return true
    }
    if (WMEURMPT.currentPURFilter & WMEURMPT.PURFilterList.hideWhitelisted && !pur.blackListed) {
      return true
    }
    if (WMEURMPT.currentPURFilter & WMEURMPT.PURFilterList.hideNotKW && (pur.data.name != null && pur.data.name.toLowerCase().indexOf(WMEURMPT.currentPURKeyWord.toLowerCase()) === -1)) {
      return true
    }
    if (WMEURMPT.currentPURFilter & WMEURMPT.PURFilterList.hideCategorie && WMEURMPT.getPURCategoriesFromCategories(pur.data.categories) !== WMEURMPT.currentPUROnlyCategorie) {
      return true
    }
    if (WMEURMPT.currentPURFilter & WMEURMPT.PURFilterList.hideArea) {
      const xy = new OpenLayers.Geometry.Point(pur.lonlat.lon, pur.lonlat.lat)
      for (let i = 0; i < WMEURMPT.areaList.custom.length; i++) {
        if (WMEURMPT.areaList.custom[i].name === WMEURMPT.currentPUROnlyArea) {
          inside = false
          filterArea = WMEURMPT.areaList.custom[i].geometryOL.geometry.components
          for (let a = 0; a < filterArea.length; a++) {
            if (Object.prototype.hasOwnProperty.call(filterArea[a], 'bintreeContainsPoint') === false) {
              if (xy.x >= filterArea[a].bounds.left && xy.x <= filterArea[a].bounds.right && xy.y >= filterArea[a].bounds.bottom && xy.y <= filterArea[a].bounds.top && filterArea[a].containsPoint(xy)) {
                inside = true
                break
              }
            } else {
              if (filterArea[a].bintreeContainsPoint(xy)) {
                inside = true
                break
              }
            }
          }
          if (inside === false) {
            return true
          }
        }
      }
      for (let i = 0; i < WMEURMPT.areaList.country.length; i++) {
        if (WMEURMPT.areaList.country[i].name === WMEURMPT.currentPUROnlyArea) {
          inside = false
          filterArea = WMEURMPT.areaList.country[i].geometryOL.geometry.components
          for (let a = 0; a < filterArea.length; a++) {
            if (Object.prototype.hasOwnProperty.call(filterArea[a], 'bintreeContainsPoint') === false) {
              if (xy.x >= filterArea[a].bounds.left && xy.x <= filterArea[a].bounds.right && xy.y >= filterArea[a].bounds.bottom && xy.y <= filterArea[a].bounds.top && filterArea[a].containsPoint(xy)) {
                inside = true
                break
              }
            } else {
              if (filterArea[a].bintreeContainsPoint(xy)) {
                inside = true
                break
              }
            }
          }
          if (inside === false) {
            return true
          }
        }
      }
    }
    return false
  }
  WMEURMPT.toggleURFilter = function (chkboxId, filter) {
    const chkbox = WMEURMPT.getId(chkboxId)
    if (chkbox == null) {
      return
    }
    if (chkbox.checked) {
      WMEURMPT.currentURFilter = WMEURMPT.currentURFilter | filter
    } else {
      WMEURMPT.currentURFilter = WMEURMPT.currentURFilter & ~filter
    }
    WMEURMPT.logDebug('current UR filter: ' + WMEURMPT.currentURFilter)
    WMEURMPT.saveOptions()
    WMEURMPT.updateIHMFromURList()
  }
  WMEURMPT.toggleURInvertFilter = function () {
    WMEURMPT.log('Switch UR filter "invert filter"')
    WMEURMPT.urtInvertFilter = this.checked
    WMEURMPT.updateIHMFromPURList()
    WMEURMPT.saveOptions()
  }
  WMEURMPT.toggleURFilterHideClosed = function () {
    WMEURMPT.log('Switch UR filter "hide closed"')
    WMEURMPT.toggleURFilter('urt-checkbox-filterHideClosed', WMEURMPT.URFilterList.hideClosed)
  }
  WMEURMPT.toggleURFilterHideWithoutCommentFromMe = function () {
    WMEURMPT.log('Switch UR filter "hide without comments from me"')
    WMEURMPT.toggleURFilter('urt-checkbox-filterHideWithoutCommentFromMe', WMEURMPT.URFilterList.hideWithoutCommentFromMe)
  }
  WMEURMPT.toggleURFilterHideWithCommentCount = function () {
    WMEURMPT.log('Switch UR filter "hide more than ' + WMEURMPT.currentURCommentsCount + ' comments"')
    WMEURMPT.toggleURFilter('urt-checkbox-filterHideWithCommentCount', WMEURMPT.URFilterList.hideWithCommentCount)
  }
  WMEURMPT.toggleURFilterHideNoNewComment = function () {
    WMEURMPT.log('Switch UR filter "hide no new comment"')
    WMEURMPT.toggleURFilter('urt-checkbox-filterHideNoNewComment', WMEURMPT.URFilterList.hideNoNewComment)
  }
  WMEURMPT.toggleURFilterHideOutOfMyDriveArea = function () {
    WMEURMPT.log('Switch UR filter "hide out of my drive area"')
    WMEURMPT.toggleURFilter('urt-checkbox-filterHideOutOfMyDriveArea', WMEURMPT.URFilterList.hideOutOfMyDriveArea)
  }
  WMEURMPT.toggleURFilterHideOutOfMyManagedArea = function () {
    WMEURMPT.log('Switch UR filter "hide out of my managed area"')
    WMEURMPT.toggleURFilter('urt-checkbox-filterHideOutOfMyManagedArea', WMEURMPT.URFilterList.hideOutOfMyManagedArea)
  }
  WMEURMPT.toggleURFilterHideVisited = function () {
    WMEURMPT.log('Switch UR filter "hide visited"')
    WMEURMPT.toggleURFilter('urt-checkbox-filterHideVisited', WMEURMPT.URFilterList.hideVisited)
  }
  WMEURMPT.toggleURFilterHideBlacklisted = function () {
    WMEURMPT.log('Switch UR filter "hide blacklisted"')
    if (WMEURMPT.getId('urt-checkbox-filterHideBlacklisted').checked) {
      WMEURMPT.getId('urt-checkbox-filterHideWhitelisted').checked = false
      WMEURMPT.toggleURFilterHideWhitelisted()
    }
    WMEURMPT.toggleURFilter('urt-checkbox-filterHideBlacklisted', WMEURMPT.URFilterList.hideBlacklisted)
  }
  WMEURMPT.toggleURFilterHideWhitelisted = function () {
    WMEURMPT.log('Switch UR filter "hide white listed"')
    if (WMEURMPT.getId('urt-checkbox-filterHideWhitelisted').checked) {
      WMEURMPT.getId('urt-checkbox-filterHideBlacklisted').checked = false
      WMEURMPT.toggleURFilterHideBlacklisted()
    }
    WMEURMPT.toggleURFilter('urt-checkbox-filterHideWhitelisted', WMEURMPT.URFilterList.hideWhitelisted)
  }
  WMEURMPT.toggleURFilterHideGE = function () {
    WMEURMPT.log('Switch UR filter "hide General Error"')
    WMEURMPT.toggleURFilter('urt-checkbox-filterHideGE', WMEURMPT.URFilterList.hideGE)
  }
  WMEURMPT.toggleURFilterHideNotKW = function () {
    WMEURMPT.log('Switch UR filter "hide not matching keyword": ' + WMEURMPT.currentURKeyWord)
    WMEURMPT.toggleURFilter('urt-checkbox-filterHideNotKW', WMEURMPT.URFilterList.hideNotKW)
  }
  WMEURMPT.toggleURFilterHideLimitTo = function () {
    WMEURMPT.log('Switch UR filter "hide over limit: "' + WMEURMPT.currentURLimitTo)
    WMEURMPT.toggleURFilter('urt-checkbox-filterHideLimitTo', WMEURMPT.URFilterList.hideLimitTo)
  }
  WMEURMPT.toggleURFilterHideOnlyType = function () {
    WMEURMPT.log('Switch UR filter "hide all but type: "' + WMEURMPT.currentUROnlyType)
    WMEURMPT.toggleURFilter('urt-checkbox-filterHideOnlyType', WMEURMPT.URFilterList.hideType)
  }
  WMEURMPT.toggleURFilterHideOnlyArea = function () {
    WMEURMPT.log('Switch UR filter "hide all but area: "' + WMEURMPT.currentUROnlyArea)
    WMEURMPT.toggleURFilter('urt-checkbox-filterHideOnlyArea', WMEURMPT.URFilterList.hideArea)
  }
  WMEURMPT.toggleURFilterHideLastCommentFromEditor = function () {
    WMEURMPT.log('Switch UR filter "hide last comment from editor"')
    WMEURMPT.toggleURFilter('urt-checkbox-filterHideLastCommentFromEditor', WMEURMPT.URFilterList.hideLastCommentFromEditor)
  }
  WMEURMPT.toggleURFilterHideTagged = function () {
    WMEURMPT.log('Switch UR filter "hide tagged"')
    WMEURMPT.toggleURFilter('urt-checkbox-filterHideTagged', WMEURMPT.URFilterList.hideTagged)
  }
  WMEURMPT.toggleMPFilter = function (chkboxId, filter) {
    const chkbox = WMEURMPT.getId(chkboxId)
    if (chkbox == null) {
      return
    }
    if (chkbox.checked) {
      WMEURMPT.currentMPFilter = WMEURMPT.currentMPFilter | filter
    } else {
      WMEURMPT.currentMPFilter = WMEURMPT.currentMPFilter & ~filter
    }
    WMEURMPT.log('current MP filter: ' + WMEURMPT.currentMPFilter)
    WMEURMPT.updateIHMFromMPList()
  }
  WMEURMPT.toggleMPFilterHideClosed = function () {
    WMEURMPT.log('Switch MP filter "hide closed"')
    WMEURMPT.toggleMPFilter('mpt-checkbox-filterHideClosed', WMEURMPT.MPFilterList.hideClosed)
  }
  WMEURMPT.toggleMPFilterHideOutOfMyDriveArea = function () {
    WMEURMPT.log('Switch MP filter "hide out of my drive area"')
    WMEURMPT.toggleMPFilter('mpt-checkbox-filterHideOutOfMyDriveArea', WMEURMPT.MPFilterList.hideOutOfMyDriveArea)
  }
  WMEURMPT.toggleMPFilterHideOutOfMyManagedArea = function () {
    WMEURMPT.log('Switch MP filter "hide out of my managed area"')
    WMEURMPT.toggleMPFilter('mpt-checkbox-filterHideOutOfMyManagedArea', WMEURMPT.MPFilterList.hideOutOfMyManagedArea)
  }
  WMEURMPT.toggleMPFilterHideVisited = function () {
    WMEURMPT.log('Switch MP filter "hide visited"')
    WMEURMPT.toggleMPFilter('mpt-checkbox-filterHideVisited', WMEURMPT.MPFilterList.hideVisited)
  }
  WMEURMPT.toggleMPFilterHideBlacklisted = function () {
    WMEURMPT.log('Switch MP filter "hide blacklisted"')
    if (WMEURMPT.getId('mpt-checkbox-filterHideBlacklisted').checked) {
      WMEURMPT.getId('mpt-checkbox-filterHideWhitelisted').checked = false
      WMEURMPT.toggleMPFilterHideWhitelisted()
    }
    WMEURMPT.toggleMPFilter('mpt-checkbox-filterHideBlacklisted', WMEURMPT.MPFilterList.hideBlacklisted)
  }
  WMEURMPT.toggleMPFilterHideWhitelisted = function () {
    WMEURMPT.log('Switch MP filter "hide whitelisted"')
    if (WMEURMPT.getId('mpt-checkbox-filterHideWhitelisted').checked) {
      WMEURMPT.getId('mpt-checkbox-filterHideBlacklisted').checked = false
      WMEURMPT.toggleMPFilterHideBlacklisted()
    }
    WMEURMPT.toggleMPFilter('mpt-checkbox-filterHideWhitelisted', WMEURMPT.MPFilterList.hideWhitelisted)
  }
  WMEURMPT.toggleMPFilterHideLimitTo = function () {
    WMEURMPT.log('Switch MP filter "hide over limit: "' + WMEURMPT.currentMPLimitTo)
    WMEURMPT.toggleMPFilter('mpt-checkbox-filterHideLimitTo', WMEURMPT.MPFilterList.hideLimitTo)
  }
  WMEURMPT.toggleMPFilterHideOnlyType = function () {
    WMEURMPT.log('Switch MP filter "hide all but type: "' + WMEURMPT.currentMPOnlyType)
    WMEURMPT.toggleMPFilter('mpt-checkbox-filterHideOnlyType', WMEURMPT.MPFilterList.hideType)
  }
  WMEURMPT.toggleMPFilterHideOnlyArea = function () {
    WMEURMPT.log('Switch MP filter "hide all but area: "' + WMEURMPT.currentMPOnlyArea)
    WMEURMPT.toggleMPFilter('mpt-checkbox-filterHideOnlyArea', WMEURMPT.MPFilterList.hideArea)
  }
  WMEURMPT.toggleMCFilter = function (chkboxId, filter) {
    const chkbox = WMEURMPT.getId(chkboxId)
    if (chkbox == null) {
      return
    }
    if (chkbox.checked) {
      WMEURMPT.currentMCFilter = WMEURMPT.currentMCFilter | filter
    } else {
      WMEURMPT.currentMCFilter = WMEURMPT.currentMCFilter & ~filter
    }
    WMEURMPT.log('current MC filter: ' + WMEURMPT.currentMCFilter)
    WMEURMPT.updateIHMFromMCList()
  }
  WMEURMPT.toggleMCFilterHideOutOfMyDriveArea = function () {
    WMEURMPT.log('Switch MC filter "hide out of my drive area"')
    WMEURMPT.toggleMCFilter('mct-checkbox-filterHideOutOfMyDriveArea', WMEURMPT.MCFilterList.hideOutOfMyDriveArea)
  }
  WMEURMPT.toggleMCFilterHideOutOfMyManagedArea = function () {
    WMEURMPT.log('Switch MC filter "hide out of my managed area"')
    WMEURMPT.toggleMCFilter('mct-checkbox-filterHideOutOfMyManagedArea', WMEURMPT.MCFilterList.hideOutOfMyManagedArea)
  }
  WMEURMPT.toggleMCFilterHideVisited = function () {
    WMEURMPT.log('Switch MC filter "hide visited"')
    WMEURMPT.toggleMCFilter('mct-checkbox-filterHideVisited', WMEURMPT.MCFilterList.hideVisited)
  }
  WMEURMPT.toggleMCFilterHideBlacklisted = function () {
    WMEURMPT.log('Switch MC filter "hide blacklisted"')
    if (WMEURMPT.getId('mct-checkbox-filterHideBlacklisted').checked) {
      WMEURMPT.getId('mct-checkbox-filterHideWhitelisted').checked = false
      WMEURMPT.toggleMCFilterHideWhitelisted()
    }
    WMEURMPT.toggleMCFilter('mct-checkbox-filterHideBlacklisted', WMEURMPT.MCFilterList.hideBlacklisted)
  }
  WMEURMPT.toggleMCFilterHideWhitelisted = function () {
    WMEURMPT.log('Switch MC filter "hide whitelisted"')
    if (WMEURMPT.getId('mct-checkbox-filterHideWhitelisted').checked) {
      WMEURMPT.getId('mct-checkbox-filterHideBlacklisted').checked = false
      WMEURMPT.toggleMCFilterHideBlacklisted()
    }
    WMEURMPT.toggleMCFilter('mct-checkbox-filterHideWhitelisted', WMEURMPT.MCFilterList.hideWhitelisted)
  }
  WMEURMPT.toggleMCFilterHideNotKW = function () {
    WMEURMPT.log('Switch MC filter "hide not matching keyword": ' + WMEURMPT.currentMCKeyWord)
    WMEURMPT.toggleMCFilter('mct-checkbox-filterHideNotKW', WMEURMPT.MCFilterList.hideNotKW)
  }
  WMEURMPT.toggleMCFilterHideLimitTo = function () {
    WMEURMPT.log('Switch MC filter "hide over limit: "' + WMEURMPT.currentMCLimitTo)
    WMEURMPT.toggleMCFilter('mct-checkbox-filterHideLimitTo', WMEURMPT.MCFilterList.hideLimitTo)
  }
  WMEURMPT.toggleMCFilterHideOnlyArea = function () {
    WMEURMPT.log('Switch MC filter "hide all but area: "' + WMEURMPT.currentMCOnlyArea)
    WMEURMPT.toggleMCFilter('mct-checkbox-filterHideOnlyArea', WMEURMPT.MCFilterList.hideArea)
  }
  WMEURMPT.togglePURFilter = function (chkboxId, filter) {
    const chkbox = WMEURMPT.getId(chkboxId)
    if (chkbox == null) {
      return
    }
    if (chkbox.checked) {
      WMEURMPT.currentPURFilter = WMEURMPT.currentPURFilter | filter
    } else {
      WMEURMPT.currentPURFilter = WMEURMPT.currentPURFilter & ~filter
    }
    WMEURMPT.log('current PUR filter: ' + WMEURMPT.currentPURFilter)
    WMEURMPT.updateIHMFromPURList()
  }
  WMEURMPT.togglePURFilterHideOutOfMyDriveArea = function () {
    WMEURMPT.log('Switch PUR filter "hide out of my drive area"')
    WMEURMPT.togglePURFilter('purt-checkbox-filterHideOutOfMyDriveArea', WMEURMPT.PURFilterList.hideOutOfMyDriveArea)
  }
  WMEURMPT.togglePURFilterHideOutOfMyManagedArea = function () {
    WMEURMPT.log('Switch PUR filter "hide out of my managed area"')
    WMEURMPT.togglePURFilter('purt-checkbox-filterHideOutOfMyManagedArea', WMEURMPT.PURFilterList.hideOutOfMyManagedArea)
  }
  WMEURMPT.togglePURFilterHideVisited = function () {
    WMEURMPT.log('Switch PUR filter "hide visited"')
    WMEURMPT.togglePURFilter('purt-checkbox-filterHideVisited', WMEURMPT.PURFilterList.hideVisited)
  }
  WMEURMPT.togglePURFilterHideBlacklisted = function () {
    WMEURMPT.log('Switch PUR filter "hide blacklisted"')
    if (WMEURMPT.getId('purt-checkbox-filterHideBlacklisted').checked) {
      WMEURMPT.getId('purt-checkbox-filterHideWhitelisted').checked = false
      WMEURMPT.togglePURFilterHideWhitelisted()
    }
    WMEURMPT.togglePURFilter('purt-checkbox-filterHideBlacklisted', WMEURMPT.PURFilterList.hideBlacklisted)
  }
  WMEURMPT.togglePURFilterHideWhitelisted = function () {
    WMEURMPT.log('Switch PUR filter "hide whitelisted"')
    if (WMEURMPT.getId('purt-checkbox-filterHideWhitelisted').checked) {
      WMEURMPT.getId('purt-checkbox-filterHideBlacklisted').checked = false
      WMEURMPT.togglePURFilterHideBlacklisted()
    }
    WMEURMPT.togglePURFilter('purt-checkbox-filterHideWhitelisted', WMEURMPT.PURFilterList.hideWhitelisted)
  }
  WMEURMPT.togglePURFilterHideNotKW = function () {
    WMEURMPT.log('Switch PUR filter "hide not matching keyword": ' + WMEURMPT.currentPURKeyWord)
    WMEURMPT.togglePURFilter('purt-checkbox-filterHideNotKW', WMEURMPT.PURFilterList.hideNotKW)
  }
  WMEURMPT.togglePURFilterHideOnlyCategorie = function () {
    WMEURMPT.log('Switch PUR filter "hide only categorie: "' + WMEURMPT.currentPUROnlyCategorie)
    WMEURMPT.togglePURFilter('purt-checkbox-filterHideOnlyCategorie', WMEURMPT.PURFilterList.hideCategorie)
  }
  WMEURMPT.togglePURFilterHideLimitTo = function () {
    WMEURMPT.log('Switch PUR filter "hide over limit: "' + WMEURMPT.currentPURLimitTo)
    WMEURMPT.togglePURFilter('purt-checkbox-filterHideLimitTo', WMEURMPT.PURFilterList.hideLimitTo)
  }
  WMEURMPT.togglePURFilterHideOnlyArea = function () {
    WMEURMPT.log('Switch PUR filter "hide all but area: "' + WMEURMPT.currentPUROnlyArea)
    WMEURMPT.togglePURFilter('purt-checkbox-filterHideOnlyArea', WMEURMPT.PURFilterList.hideArea)
  }
  WMEURMPT.URCommentsCountChanged = function () {
    WMEURMPT.currentURCommentsCount = this.value
    if (WMEURMPT.getId('urt-checkbox-filterHideWithCommentCount').checked) {
      WMEURMPT.log('Hide UR comments greater than: ' + WMEURMPT.currentURCommentsCount)
      WMEURMPT.updateIHMFromURList()
    }
    WMEURMPT.saveOptions()
  }
  WMEURMPT.URKeywordChanged = function () {
    WMEURMPT.currentURKeyWord = this.value
    if (WMEURMPT.getId('urt-checkbox-filterHideNotKW').checked) {
      WMEURMPT.updateIHMFromURList()
    }
    WMEURMPT.saveOptions()
  }
  WMEURMPT.MCKeywordChanged = function () {
    WMEURMPT.currentMCKeyWord = this.value
    if (WMEURMPT.getId('mct-checkbox-filterHideNotKW').checked) {
      WMEURMPT.updateIHMFromMCList()
    }
    WMEURMPT.saveOptions()
  }
  WMEURMPT.PURKeywordChanged = function () {
    WMEURMPT.currentPURKeyWord = this.value
    if (WMEURMPT.getId('purt-checkbox-filterHideNotKW').checked) {
      WMEURMPT.updateIHMFromPURList()
    }
    WMEURMPT.saveOptions()
  }
  WMEURMPT.URLimitToChanged = function () {
    WMEURMPT.currentURLimitTo = parseInt(this.value)
    if (isNaN(WMEURMPT.currentURLimitTo)) {
      WMEURMPT.currentURLimitTo = 100
    }
    if (WMEURMPT.getId('urt-checkbox-filterHideLimitTo').checked) {
      WMEURMPT.log('Limit UR list to: ' + WMEURMPT.currentURLimitTo)
      WMEURMPT.updateIHMFromURList()
    }
    WMEURMPT.saveOptions()
  }
  WMEURMPT.MPLimitToChanged = function () {
    WMEURMPT.currentMPLimitTo = parseInt(this.value)
    if (isNaN(WMEURMPT.currentMPLimitTo)) {
      WMEURMPT.currentMPLimitTo = 100
    }
    if (WMEURMPT.getId('mpt-checkbox-filterHideLimitTo').checked) {
      WMEURMPT.log('Limit MP list to: ' + WMEURMPT.currentMPLimitTo)
      WMEURMPT.updateIHMFromMPList()
    }
    WMEURMPT.saveOptions()
  }
  WMEURMPT.MCLimitToChanged = function () {
    WMEURMPT.currentMCLimitTo = parseInt(this.value)
    if (isNaN(WMEURMPT.currentMCLimitTo)) {
      WMEURMPT.currentMCLimitTo = 100
    }
    if (WMEURMPT.getId('mct-checkbox-filterHideLimitTo').checked) {
      WMEURMPT.log('Limit MC list to: ' + WMEURMPT.currentMCLimitTo)
      WMEURMPT.updateIHMFromMCList()
    }
    WMEURMPT.saveOptions()
  }
  WMEURMPT.PURLimitToChanged = function () {
    WMEURMPT.currentPURLimitTo = parseInt(this.value)
    if (isNaN(WMEURMPT.currentPURLimitTo)) {
      WMEURMPT.currentPURLimitTo = 100
    }
    if (WMEURMPT.getId('purt-checkbox-filterHideLimitTo').checked) {
      WMEURMPT.log('Limit PUR list to: ' + WMEURMPT.currentPURLimitTo)
      WMEURMPT.updateIHMFromPURList()
    }
    WMEURMPT.saveOptions()
  }
  WMEURMPT.UROnlyTypeChanged = function () {
    WMEURMPT.currentUROnlyType = parseInt(this.value)
    if (WMEURMPT.getId('urt-checkbox-filterHideOnlyType').checked) {
      WMEURMPT.log('Hide all UR but type: ' + WMEURMPT.currentUROnlyType)
      WMEURMPT.updateIHMFromURList()
    }
    WMEURMPT.saveOptions()
  }
  WMEURMPT.MPOnlyTypeChanged = function () {
    WMEURMPT.currentMPOnlyType = parseInt(this.value)
    if (WMEURMPT.getId('mpt-checkbox-filterHideOnlyType').checked) {
      WMEURMPT.log('Hide all MP but type: ' + WMEURMPT.currentMPOnlyType)
      WMEURMPT.updateIHMFromMPList()
    }
    WMEURMPT.saveOptions()
  }
  WMEURMPT.PUROnlyCategorieChanged = function () {
    WMEURMPT.currentPUROnlyCategorie = this.value
    if (WMEURMPT.getId('purt-checkbox-filterHideOnlyCategorie').checked) {
      WMEURMPT.log('Hide all PUR but type: ' + WMEURMPT.currentPUROnlyCategorie)
      WMEURMPT.updateIHMFromPURList()
    }
    WMEURMPT.saveOptions()
  }
  WMEURMPT.UROnlyAreaChanged = function () {
    WMEURMPT.currentUROnlyArea = this.value
    if (WMEURMPT.getId('urt-checkbox-filterHideOnlyArea').checked) {
      WMEURMPT.log('Hide all UR but area: ' + WMEURMPT.currentUROnlyArea)
      WMEURMPT.updateIHMFromURList()
    }
    WMEURMPT.saveOptions()
  }
  WMEURMPT.MPOnlyAreaChanged = function () {
    WMEURMPT.currentMPOnlyArea = this.value
    if (WMEURMPT.getId('mpt-checkbox-filterHideOnlyArea').checked) {
      WMEURMPT.log('Hide all MP but area: ' + WMEURMPT.currentMPOnlyArea)
      WMEURMPT.updateIHMFromMPList()
    }
    WMEURMPT.saveOptions()
  }
  WMEURMPT.MCOnlyAreaChanged = function () {
    WMEURMPT.currentMCOnlyArea = this.value
    if (WMEURMPT.getId('mct-checkbox-filterHideOnlyArea').checked) {
      WMEURMPT.log('Hide all MC but area: ' + WMEURMPT.currentMCOnlyArea)
      WMEURMPT.updateIHMFromMCList()
    }
    WMEURMPT.saveOptions()
  }
  WMEURMPT.PUROnlyAreaChanged = function () {
    WMEURMPT.currentPUROnlyArea = this.value
    if (WMEURMPT.getId('purt-checkbox-filterHideOnlyArea').checked) {
      WMEURMPT.log('Hide all PUR but area: ' + WMEURMPT.currentPUROnlyArea)
      WMEURMPT.updateIHMFromPURList()
    }
    WMEURMPT.saveOptions()
  }
  WMEURMPT.togglePURInvertFilter = function () {
    WMEURMPT.log('Change PUR filter "invert filter"')
    WMEURMPT.purInvertFilter = this.checked
    WMEURMPT.updateIHMFromPURList()
    WMEURMPT.saveOptions()
  }
  WMEURMPT.refreshAreasCombolist = function (selectEl, defaultSelected) {
    if (selectEl == null) {
      WMEURMPT.log('Error no filter area')
      return
    }
    let content = ''
    for (let i = 0; i < WMEURMPT.areaList.country.length; i++) {
      content += '<option value="' + WMEURMPT.areaList.country[i].name + '"' + (defaultSelected === WMEURMPT.areaList.country[i].name ? ' selected' : '') + '>' + WMEURMPT.areaList.country[i].name + '</option>'
    }
    for (let i = 0; i < WMEURMPT.areaList.custom.length; i++) {
      content += '<option value="' + WMEURMPT.areaList.custom[i].name + '"' + (defaultSelected === WMEURMPT.areaList.custom[i].name ? ' selected' : '') + '>' + WMEURMPT.areaList.custom[i].name + '</option>'
    }
    if (content === '') {
      selectEl.parentNode.style.display = 'none'
    } else {
      selectEl.parentNode.style.display = 'block'
      WMEURMPT.removeChildElements(selectEl)
      selectEl.innerHTML = WMEURMPT.convertHtml(content)
    }
  }
  WMEURMPT.addCountryToAreaList = function () {
    const country = WMEURMPT.getId('urmpt-countryList').value
    WMEURMPT.log('Add country to filter list: ' + country)
    const area = new WMEURMPT.URT_AREA()
    area.category = 'country'
    const areaPath = country.split('->')
    if (areaPath.length > 1) {
      area.subset = true
      area.name = areaPath[areaPath.length - 1]
      area.parent = areaPath[0]
      for (let i = 1; i < areaPath.length - 1; i++) {
        if (i % 2 === 1) {
          area.parent += '.'
        } else {
          area.parent += '/'
        }
        area.parent += areaPath[i]
      }
    } else {
      area.name = country
    }
    area.getGeometryFromServer(WMEURMPT.newCountryGeometryAvailable)
  }
  WMEURMPT.newCountryGeometryAvailable = function (area) {
    if (area == null) {
      alert('Error while getting area from server.' + NL + 'Please, retry later.')
      return
    }
    WMEURMPT.removeCountryFromAreaList(area)
    WMEURMPT.areaList.country.push(area)
    WMEURMPT.updateScanGroup()
  }
  WMEURMPT.removeCountryFromAreaList = function (country) {
    WMEURMPT.log('remove country: ' + country)
    for (let i = 0; i < WMEURMPT.areaList.country.length; i++) {
      if (WMEURMPT.areaList.country[i].name === country.name && WMEURMPT.areaList.country[i].subset === country.subset && WMEURMPT.areaList.country[i].parent === country.parent) {
        WMEURMPT.areaList.country.splice(i, 1)
        break
      }
    }
    WMEURMPT.updateScanGroup()
  }
  WMEURMPT.removeCountryIDFromAreaList = function (id) {
    WMEURMPT.areaList.country.splice(id, 1)
    WMEURMPT.updateScanGroup()
  }
  WMEURMPT.addCustomAreaFromWKTToFilterList = function () {
    const elName = WMEURMPT.getId('urmpt-areas-wktfile-name')
    if (elName.value === '') {
      alert('The name of your custom area is empty.' + NL + 'Please, fill it.')
      return
    }
    if (WMEURMPT.lastUploadedWKT === null) {
      alert('Please, choose a file before.')
      return
    }
    const ca = new WMEURMPT.URT_AREA()
    ca.category = 'custom'
    ca.name = elName.value
    WMEURMPT.log('Add CA to scan list: ' + ca.name)
    ca.geometryWKT = WMEURMPT.lastUploadedWKT
    WMEURMPT.removeCustomNameFromAreaList(ca.name)
    WMEURMPT.areaList.custom.push(ca)
    elName.value = ''
    WMEURMPT.lastUploadedWKT = null
    WMEURMPT.updateScanGroup()
  }
  WMEURMPT.handleFileSelectAddFromJSON = function (evt) {
    const files = evt.target.files
    Array.from(files).forEach(f => {
      const reader = new FileReader()
      reader.onload = (function (theFile) {
        return function (e) {
          WMEURMPT.lastUploadedJSON = e.target.result
          WMEURMPT.log('import JSON file read')
        }
      }(f))
      reader.readAsText(f)
    })
  }
  WMEURMPT.addCustomAreaFromJSONToFilterList = function () {
    if (WMEURMPT.lastUploadedJSON === null) {
      alert('Please, choose a file before.')
      return
    }
    const customAreas = JSON.parse(WMEURMPT.lastUploadedJSON)
    customAreas.forEach(function (a) {
      const ca = new WMEURMPT.URT_AREA()
      ca.category = 'custom'
      ca.name = a.name
      WMEURMPT.log('Add CA to scan list: ' + ca.name)
      ca.geometryWKT = a.geometryWKT
      WMEURMPT.removeCustomNameFromAreaList(ca.name)
      WMEURMPT.areaList.custom.push(ca)
    })
    WMEURMPT.lastUploadedJSON = null
    WMEURMPT.updateScanGroup()
  }

  WMEURMPT.addCustomAreaFromPOIToFilterList = function () {
    const elName = WMEURMPT.getId('urmpt-areas-frompoi-name')
    if (elName.value === '') {
      alert('The name of your custom area is empty.' + NL + 'Please, fill it.')
      return
    }
    let theVenue = null
    let count = 0
    for (const v in WMEURMPT.wazeModel.venues.objects) {
      if (Object.prototype.hasOwnProperty.call(WMEURMPT.wazeModel.venues.objects, v) === false) {
        continue
      }
      const venue = WMEURMPT.wazeModel.venues.objects[v]
      if (venue.isPoint() === true) {
        continue
      }
      if (venue.attributes.id <= 0) {
        theVenue = venue
        count++
      }
    }
    if (count > 1) {
      alert('There must be only one unsaved venue.' + NL + count + ' detected.' + NL + 'Draw only one venue to convert it in a custom area.')
      return
    }
    if (count === 0) {
      alert('You must draw an area venue and not save it. Then you can add it as a custom area.')
      return
    }
    const ca = new WMEURMPT.URT_AREA()
    ca.category = 'custom'
    ca.name = elName.value
    WMEURMPT.log('Add CA to scan list: ' + ca.name)
    const theVenueGeom = theVenue.getOLGeometry()
    if (theVenueGeom.components.length !== 1) {
      alert("Can't parse the geometry")
      return
    }
    ca.geometryWKT = 'POLYGON (('
    const lonlats = []
    for (let i = 0; i < theVenueGeom.components[0].components.length; i++) {
      const lonlat = OpenLayers.Layer.SphericalMercator.inverseMercator(theVenueGeom.components[0].components[i].x, theVenueGeom.components[0].components[i].y)
      lonlats.push(lonlat.lon + ' ' + lonlat.lat)
    }
    ca.geometryWKT += lonlats.join(',')
    ca.geometryWKT += '))'
    WMEURMPT.removeCustomNameFromAreaList(ca.name)
    WMEURMPT.areaList.custom.push(ca)
    elName.value = ''
    if (confirm('Undo all edits?')) {
      WMEURMPT.wazeModel.actionManager.undoAll()
    }
    WMEURMPT.updateScanGroup()
  }

  WMEURMPT.addCustomAreaToFilterList = function () {
    const elName = WMEURMPT.getId('urmpt-areas-name')
    const elTLlon = WMEURMPT.getId('urmpt-areas-tl-lon')
    const elBRlon = WMEURMPT.getId('urmpt-areas-br-lon')
    const elTLlat = WMEURMPT.getId('urmpt-areas-tl-lat')
    const elBRlat = WMEURMPT.getId('urmpt-areas-br-lat')
    if (elName.value === '') {
      alert('The name of your custom area is empty.' + NL + 'Please, fill it.')
      return
    }
    if (elTLlon.value === '' || elBRlon.value === '' || elTLlat.value === '' || elBRlat.value === '') {
      alert('The lon/lat coords are not filled correctly.')
      return
    }
    const ca = new WMEURMPT.URT_AREA()
    ca.category = 'custom'
    ca.name = elName.value
    WMEURMPT.log('Add CA to scan list: ' + ca.name)
    const lonMin = elTLlon.value
    const lonMax = elBRlon.value
    const latMin = elTLlat.value
    const latMax = elBRlat.value
    ca.geometryWKT = 'POLYGON ((' + lonMin + ' ' + latMin + ',' + lonMax + ' ' + latMin + ',' + lonMax + ' ' + latMax + ',' + lonMin + ' ' + latMax + ',' + lonMin + ' ' + latMin + '))'
    WMEURMPT.removeCustomNameFromAreaList(ca.name)
    WMEURMPT.areaList.custom.push(ca)
    elName.value = ''
    elTLlon.value = ''
    elBRlon.value = ''
    elTLlat.value = ''
    elBRlat.value = ''
    WMEURMPT.updateScanGroup()
  }

  WMEURMPT.removeCustomNameFromAreaList = function (areaName) {
    for (let c = 0; c < WMEURMPT.areaList.custom.length; c++) {
      if (WMEURMPT.areaList.custom[c].name === areaName) {
        WMEURMPT.areaList.custom.splice(c, 1)
        WMEURMPT.log('removed CA: ' + areaName)
        break
      }
    }
    WMEURMPT.updateScanGroup()
  }

  WMEURMPT.editCustomArea = function (areaName) {
    for (let c = 0; c < WMEURMPT.areaList.custom.length; c++) {
      WMEURMPT.getId('urmpt-area-custom-edit-' + WMEURMPT.areaList.custom[c].name).style.display = 'none'
      if (WMEURMPT.areaList.custom[c].name === areaName) {
        WMEURMPT.getId('urmpt-area-custom-save-' + WMEURMPT.areaList.custom[c].name).style.display = 'inline'
        const area = WMEURMPT.areaList.custom[c]
        const FeatureLandmark = require('Waze/Feature/Vector/Landmark')

        const convProjection = area.geometryOL.geometry.transform(
          new OpenLayers.Projection('EPSG:4326'),
          WMEURMPT.wazeMap.getProjectionObject()
        )

        const landmark = new FeatureLandmark({ geoJSONGeometry: W.userscripts.toGeoJSONGeometry(convProjection) })
        const center = area.geometryOL.geometry.getCentroid()
        const xy = OpenLayers.Layer.SphericalMercator.forwardMercator(center.x, center.y)
        WMEURMPT.wazeMap.setCenter(xy)
        landmark.attributes.categories = ['OTHER']
        const AddLandmark = require('Waze/Action/AddLandmark')
        // eslint-disable-next-line no-undef
        W.model.actionManager.add(new AddLandmark(landmark), _.defer(function () {
          W.selectionManager.setSelectedModels([landmark])
        }))
      }
    }
  }

  WMEURMPT.saveEditedCustomArea = function (areaName) {
    let theVenue = null
    let count = 0
    for (const v in WMEURMPT.wazeModel.venues.objects) {
      if (Object.prototype.hasOwnProperty.call(WMEURMPT.wazeModel.venues.objects, v) === false) {
        continue
      }
      const venue = WMEURMPT.wazeModel.venues.objects[v]
      if (venue.isPoint() === true) {
        continue
      }
      if (venue.attributes.id <= 0) {
        theVenue = venue
        count++
      }
    }
    if (count > 1) {
      // eslint-disable-next-line quotes
      alert('There must be only one unsaved venue.' + NL + count + ' detected.' + NL + 'Draw only one venue to convert it in a custom area.')
      WMEURMPT.updateScanGroup()
      return
    }
    if (count === 0) {
      alert('You must draw an area venue and not save it. Then you can add it as a custom area.')
      WMEURMPT.updateScanGroup()
      return
    }
    const theVenueGeom = theVenue.getOLGeometry()
    if (theVenueGeom.components.length !== 1) {
      alert("Can't parse the geometry")
      WMEURMPT.updateScanGroup()
      return
    }
    WMEURMPT.removeCustomNameFromAreaList(areaName)
    const ca = new WMEURMPT.URT_AREA()
    ca.category = 'custom'
    ca.name = areaName
    ca.geometryWKT = 'POLYGON (('
    const lonlats = []
    for (let i = 0; i < theVenueGeom.components[0].components.length; i++) {
      const lonlat = OpenLayers.Layer.SphericalMercator.inverseMercator(theVenueGeom.components[0].components[i].x, theVenueGeom.components[0].components[i].y)
      lonlats.push(lonlat.lon + ' ' + lonlat.lat)
    }
    ca.geometryWKT += lonlats.join(',')
    ca.geometryWKT += '))'
    WMEURMPT.areaList.custom.push(ca)
    if (confirm('Undo all edits?')) {
      WMEURMPT.wazeModel.actionManager.undoAll()
    }
    WMEURMPT.updateScanGroup()
  }

  WMEURMPT.exportAllCAToJSON = function () {
    this.setAttribute('download', 'URMPT_CustomAreas_' + WMEURMPT.me.getUsername() + '.json')
    this.href = 'data:application/octet-stream;charset=utf-8;base64,' + btoa(JSON.stringify(WMEURMPT.areaList.custom.map(function (e) {
      return { name: e.name, geometryWKT: e.geometryWKT }
    })))
  }

  WMEURMPT.updateScanGroup = function () {
    const scanGroup = WMEURMPT.getId('urt-a-scanGroup')
    const countryScanList = WMEURMPT.getId('urmpt-countryscanlist')
    const customAreaScanList = WMEURMPT.getId('urmpt-custom-scan-list')
    WMEURMPT.removeChildElements(scanGroup)
    scanGroup.innerHTML = WMEURMPT.convertHtml('SCAN: ')
    if (countryScanList != null) {
      WMEURMPT.removeChildElements(countryScanList)
      countryScanList.innerHTML = WMEURMPT.convertHtml('')
    }
    WMEURMPT.removeChildElements(customAreaScanList)
    customAreaScanList.innerHTML = WMEURMPT.convertHtml('')
    let elt = document.createElement('a', 'urt-a-DriveArea')
    elt.innerHTML = WMEURMPT.convertHtml('Drive area')
    elt.href = '#'
    elt.onclick = WMEURMPT.getFunctionWithArgs(WMEURMPT.updateListsFromManualScan, [{ type: 'driveArea' }])
    scanGroup.appendChild(elt)
    if (WMEURMPT.uam) {
      elt = document.createElement('span')
      elt.innerHTML = ' | '
      scanGroup.appendChild(elt)
      elt = document.createElement('a', 'urt-a-ManagedArea')
      elt.innerHTML = WMEURMPT.convertHtml('Managed area')
      elt.href = '#'
      elt.onclick = WMEURMPT.getFunctionWithArgs(WMEURMPT.updateListsFromManualScan, [{ type: 'managedArea' }])
      scanGroup.appendChild(elt)
    }
    if (WMEURMPT.areaList.country.length === 0 && (WMEURMPT.ul >= 8 || WMEURMPT.me.isCountryManager())) {
      scanGroup.insertAdjacentHTML('beforeend', WMEURMPT.convertHtml('<br/><font color="#C00000">You are a rank 4+ editor. In the areas tab, you can select a country or a subset for state managers in the list and add it to your scan list!'))
    }
    for (let c = 0; c < WMEURMPT.areaList.country.length; c++) {
      if (WMEURMPT.areaList.country[c].geometryOL == null) {
        WMEURMPT.areaList.country[c].geometryOL = (new OpenLayers.Format.WKT()).read(WMEURMPT.areaList.country[c].geometryWKT)
        if (WMEURMPT.areaList.country[c].geometryOL == null || Object.prototype.hasOwnProperty.call(WMEURMPT.areaList.country[c].geometryOL, 'geometry') === false) {
          WMEURMPT.log('Error on area ' + WMEURMPT.areaList.country[c].name + '. Removing it... :(')
          WMEURMPT.areaList.country.splice(c, 1)
          c--
          continue
        }
        for (let j = 0; j < WMEURMPT.areaList.country[c].geometryOL.geometry.components.length; j++) {
          WMEURMPT.areaList.country[c].geometryOL.geometry.components[j].calculateBounds()
          WMEURMPT.bintreeGeometry(WMEURMPT.areaList.country[c].geometryOL.geometry.components[j])
        }
      }
      elt = WMEURMPT.createElement('span')
      elt.innerHTML = WMEURMPT.convertHtml(' | ')
      scanGroup.appendChild(elt)
      elt = WMEURMPT.createElement('a', 'urt-a-scan' + WMEURMPT.areaList.country[c].name)
      elt.innerHTML = WMEURMPT.convertHtml(WMEURMPT.areaList.country[c].name.replace(/_/g, ' '))
      elt.href = '#'
      elt.onclick = WMEURMPT.getFunctionWithArgs(WMEURMPT.updateListsFromManualScan, [{ type: 'country', name: WMEURMPT.areaList.country[c].name }])
      scanGroup.appendChild(elt)
      if (countryScanList != null) {
        elt = WMEURMPT.createElement('div')
        elt.innerHTML = WMEURMPT.convertHtml(WMEURMPT.areaList.country[c].name.replace(/_/g, ' ') + ' ')
        const GELink = WMEURMPT.createElement('a')
        GELink.href = '#'
        GELink.innerHTML = WMEURMPT.convertHtml('<img style="height: 15px;" src="data:image/png;base64,' + WMEURMPT.icon_ge + '" />')
        GELink.title = 'Show in google earth'
        GELink.onclick = WMEURMPT.getFunctionWithArgs(WMEURMPT.showAreaInGoogleEarth, [{ type: 'country', name: WMEURMPT.areaList.country[c].name }])
        elt.appendChild(GELink)
        const WKTLink = WMEURMPT.createElement('a')
        WKTLink.href = '#'
        WKTLink.innerHTML = WMEURMPT.convertHtml('WKT')
        WKTLink.title = 'Export to WKT'
        WKTLink.onclick = WMEURMPT.getFunctionWithArgs(WMEURMPT.showAreaInWKT, [{ type: 'country', name: WMEURMPT.areaList.country[c].name }])
        elt.appendChild(WKTLink)
        elt.insertAdjacentHTML('beforeend', ' (')
        const removeLink = WMEURMPT.createElement('a')
        removeLink.innerHTML = WMEURMPT.convertHtml('remove')
        removeLink.href = '#'
        removeLink.onclick = WMEURMPT.getFunctionWithArgs(WMEURMPT.removeCountryIDFromAreaList, [c])
        elt.appendChild(removeLink)
        elt.insertAdjacentHTML('beforeend', ')')
        countryScanList.appendChild(elt)
      }
    }
    for (let c = 0; c < WMEURMPT.areaList.custom.length; c++) {
      if (WMEURMPT.areaList.custom[c].geometryOL == null) {
        if (WMEURMPT.areaList.custom[c].geometryWKT == null) {
          WMEURMPT.log('Invalid area. Removing it... :(')
          WMEURMPT.areaList.custom.splice(c, 1)
          c--
          continue
        }
        WMEURMPT.areaList.custom[c].geometryOL = (new OpenLayers.Format.WKT()).read(WMEURMPT.areaList.custom[c].geometryWKT)
        if (WMEURMPT.areaList.custom[c].geometryOL == null || Object.prototype.hasOwnProperty.call(WMEURMPT.areaList.custom[c].geometryOL, 'geometry') === false) {
          WMEURMPT.log('Error on area ' + WMEURMPT.areaList.custom[c].name + '. Removing it... :(')
          WMEURMPT.areaList.custom.splice(c, 1)
          c--
          continue
        }
        for (let j = 0; j < WMEURMPT.areaList.custom[c].geometryOL.geometry.components.length; j++) {
          WMEURMPT.areaList.custom[c].geometryOL.geometry.components[j].calculateBounds()
          WMEURMPT.bintreeGeometry(WMEURMPT.areaList.custom[c].geometryOL.geometry.components[j])
        }
      }
      elt = WMEURMPT.createElement('span')
      elt.innerHTML = WMEURMPT.convertHtml(' | ')
      scanGroup.appendChild(elt)
      elt = WMEURMPT.createElement('a', 'urt-a-scan' + WMEURMPT.areaList.custom[c].name)
      elt.innerHTML = WMEURMPT.convertHtml(WMEURMPT.areaList.custom[c].name.replace(/_/g, ' '))
      elt.href = '#'
      elt.onclick = WMEURMPT.getFunctionWithArgs(WMEURMPT.updateListsFromManualScan, [{ type: 'custom', name: WMEURMPT.areaList.custom[c].name }])
      scanGroup.appendChild(elt)
      if (customAreaScanList != null) {
        elt = WMEURMPT.createElement('div')
        elt.innerHTML = WMEURMPT.convertHtml(WMEURMPT.areaList.custom[c].name.replace(/_/g, ' ') + ' ')
        const GELink = WMEURMPT.createElement('a')
        GELink.href = '#'
        GELink.innerHTML = WMEURMPT.convertHtml('<img style="height: 15px;" src="data:image/png;base64,' + WMEURMPT.icon_ge + '" />')
        GELink.title = 'Show in google earth'
        GELink.onclick = WMEURMPT.getFunctionWithArgs(WMEURMPT.showAreaInGoogleEarth, [{ type: 'custom', name: WMEURMPT.areaList.custom[c].name }])
        elt.appendChild(GELink)
        const WKTLink = WMEURMPT.createElement('a')
        WKTLink.href = '#'
        WKTLink.innerHTML = WMEURMPT.convertHtml('WKT')
        WKTLink.title = 'Export to WKT'
        WKTLink.onclick = WMEURMPT.getFunctionWithArgs(WMEURMPT.showAreaInWKT, [{ type: 'custom', name: WMEURMPT.areaList.custom[c].name }])
        elt.appendChild(WKTLink)
        elt.insertAdjacentHTML('beforeend', ' ')
        const editLink = WMEURMPT.createElement('a')
        editLink.href = '#'
        editLink.id = 'urmpt-area-custom-edit-' + WMEURMPT.areaList.custom[c].name
        editLink.innerHTML = WMEURMPT.convertHtml('Edit')
        editLink.title = 'Edit as unsaved landmark'
        editLink.onclick = WMEURMPT.getFunctionWithArgs(WMEURMPT.editCustomArea, [WMEURMPT.areaList.custom[c].name])
        elt.appendChild(editLink)
        elt.insertAdjacentHTML('beforeend', ' ')
        const saveLink = WMEURMPT.createElement('a')
        saveLink.href = '#'
        saveLink.id = 'urmpt-area-custom-save-' + WMEURMPT.areaList.custom[c].name
        saveLink.style.display = 'none'
        saveLink.innerHTML = WMEURMPT.convertHtml('Save')
        saveLink.title = 'Save landmark'
        saveLink.onclick = WMEURMPT.getFunctionWithArgs(WMEURMPT.saveEditedCustomArea, [WMEURMPT.areaList.custom[c].name])
        elt.appendChild(saveLink)
        elt.insertAdjacentHTML('beforeend', ' (')
        const removeLink = WMEURMPT.createElement('a')
        removeLink.innerHTML = WMEURMPT.convertHtml('remove')
        removeLink.href = '#'
        removeLink.onclick = WMEURMPT.getFunctionWithArgs(WMEURMPT.removeCustomNameFromAreaList, [WMEURMPT.areaList.custom[c].name])
        elt.appendChild(removeLink)
        elt.insertAdjacentHTML('beforeend', ')')
        customAreaScanList.appendChild(elt)
      }
    }
    const ael = WMEURMPT.createElement('a')
    ael.href = '#'
    ael.innerHTML = WMEURMPT.convertHtml('Export to JSON')
    ael.onclick = WMEURMPT.exportAllCAToJSON
    customAreaScanList.appendChild(ael)
    WMEURMPT.refreshAreasCombolist(WMEURMPT.getId('urt-filterOnlyArea'), WMEURMPT.currentUROnlyArea)
    WMEURMPT.refreshAreasCombolist(WMEURMPT.getId('mpt-filterOnlyArea'), WMEURMPT.currentMPOnlyArea)
    WMEURMPT.refreshAreasCombolist(WMEURMPT.getId('mct-filterOnlyArea'), WMEURMPT.currentMCOnlyArea)
    WMEURMPT.refreshAreasCombolist(WMEURMPT.getId('purt-filterOnlyArea'), WMEURMPT.currentPUROnlyArea)
    WMEURMPT.currentUROnlyArea = WMEURMPT.getId('urt-filterOnlyArea').value
    WMEURMPT.currentMPOnlyArea = WMEURMPT.getId('mpt-filterOnlyArea').value
    WMEURMPT.currentMCOnlyArea = WMEURMPT.getId('mct-filterOnlyArea').value
    WMEURMPT.currentPUROnlyArea = WMEURMPT.getId('purt-filterOnlyArea').value
    WMEURMPT.saveAreas()
  }
  WMEURMPT.showAreaInGoogleEarth = function (area) {
    let template = '<?xml version="1.0" encoding="UTF-8"?><kml xmlns="http://www.opengis.net/kml/2.2" xmlns:gx="http://www.google.com/kml/ext/2.2" xmlns:kml="http://www.opengis.net/kml/2.2" xmlns:atom="http://www.w3.org/2005/Atom"><Document> <name>#AREANAME#</name> <Style id="hl"> <IconStyle> <scale>1.2</scale> </IconStyle> <LineStyle> <color>ff000000</color> <width>2</width> </LineStyle> <PolyStyle> <color>7f0000ff</color> </PolyStyle> </Style> <Style id="default"> <LineStyle> <color>ff000000</color> <width>2</width> </LineStyle> <PolyStyle> <color>7f0000ff</color> </PolyStyle> </Style> <StyleMap id="default0"> <Pair> <key>normal</key> <styleUrl>#default</styleUrl> </Pair> <Pair> <key>highlight</key> <styleUrl>#hl</styleUrl> </Pair> </StyleMap> <Placemark> <name>#AREANAME#</name> <styleUrl>#default0</styleUrl>#GEOMETRY#</Placemark></Document></kml>'
    let kmlGeometry = ''
    let geometry = null
    function geomToKML (geom) {
      let output = ''
      for (let i = 0; i < geom.length; i++) {
        output += '<Polygon><outerBoundaryIs><LinearRing><coordinates>'
        for (let p = 0; p < geom[i].components.length; p++) {
          output += geom[i].components[p].x + ',' + geom[i].components[p].y + ' '
        }
        output += '</coordinates></LinearRing></outerBoundaryIs></Polygon>'
      }
      return output
    }
    for (let i = 0; i < WMEURMPT.areaList[area.type].length; i++) {
      if (WMEURMPT.areaList[area.type][i].name === area.name) {
        geometry = WMEURMPT.areaList[area.type][i].geometryOL.geometry
        break
      }
    }
    if (geometry) {
      if (geometry.CLASS_NAME === 'OpenLayers.Geometry.MultiPolygon') {
        kmlGeometry += '<MultiGeometry>'
        for (let p = 0; p < geometry.components.length; p++) {
          kmlGeometry += geomToKML(geometry.components[p].components)
        }
        kmlGeometry += '</MultiGeometry>'
      } else {
        kmlGeometry += geomToKML(geometry.components)
      }
      template = template.replace(/#AREANAME#/g, area.name)
      template = template.replace('#GEOMETRY#', kmlGeometry)
      this.setAttribute('download', area.name + '.kml')
      this.href = 'data:application/octet-stream;charset=utf-8;base64,' + btoa(template)
    }
    return false
  }

  WMEURMPT.computeStats = function (fromURList, fromMPList, fromDate, toDate) {
    let out = ''
    out += 'URs: ' + fromURList.length + '<br/>'
    out += 'MPs: ' + fromMPList.length + '<br/>'
    const closedUR = fromURList.filter(function (value) {
      return value.data.open === false
    }).length
    const closedMP = fromMPList.filter(function (value) {
      return value.data.open === false
    }).length
    const niUR = fromURList.filter(function (value) {
      return value.data.open === false && value.data.resolution === 1
    }).length
    const soUR = closedUR - niUR
    const niMP = fromMPList.filter(function (value) {
      return value.data.open === false && value.data.resolution === 1
    }).length
    const soMP = closedMP - niMP
    out += 'URs closed: ' + closedUR + ' (' + Math.round(closedUR * 100 / fromURList.length) + '%) ' + (fromURList.length - closedUR) + ' remaining<br/>'
    out += '&nbsp;&nbsp;Not identified: ' + niUR + ' (' + Math.round(niUR * 100 / closedUR) + '%)<br/>'
    out += '&nbsp;&nbsp;Solved: ' + soUR + ' (' + Math.round(soUR * 100 / closedUR) + '%)<br/>'
    out += 'MPs closed: ' + closedMP + ' (' + Math.round(closedMP * 100 / fromMPList.length) + '%) ' + (fromMPList.length - closedMP) + ' remaining<br/>'
    out += '&nbsp;&nbsp;Not identified: ' + niMP + ' (' + Math.round(niMP * 100 / closedMP) + '%)<br/>'
    out += '&nbsp;&nbsp;Solved: ' + soMP + ' (' + Math.round(soMP * 100 / closedMP) + '%)<br/>'
    const urWithComment = fromURList.filter(function (value) {
      return value.data.hasComments === true
    }).length
    const urWithCommentFromReporter = fromURList.filter(function (value) {
      return value.data.hasComments === true && value.data.session.comments.filter(function (c) {
        return c.userName === 'Reporter'
      }).length !== 0
    }).length
    out += 'URs with reporter comment: ' + urWithCommentFromReporter + ' (' + Math.round(urWithCommentFromReporter * 100 / urWithComment) + '% of commented URs)<br/>'
    WMEURMPT.statsCSV += 'UR;Count;Percent' + NL
    WMEURMPT.statsCSV += 'Count;' + fromURList.length + NL
    WMEURMPT.statsCSV += 'Closed;' + closedUR + ';' + closedUR * 100 / fromURList.length + NL
    WMEURMPT.statsCSV += 'Not identified;' + niUR + ';' + niUR * 100 / closedUR + NL
    WMEURMPT.statsCSV += 'Solved;' + soUR + ';' + soUR * 100 / closedUR + NL
    WMEURMPT.statsCSV += 'With comment;' + urWithComment + ';' + urWithComment * 100 / fromURList.length + NL
    WMEURMPT.statsCSV += 'With reporter comment;' + urWithCommentFromReporter + ';' + urWithCommentFromReporter * 100 / urWithComment + NL
    WMEURMPT.statsCSV += 'MP;Count;Percent' + NL
    WMEURMPT.statsCSV += 'Count;' + fromMPList.length + NL
    WMEURMPT.statsCSV += 'Closed;' + closedMP + ';' + closedMP * 100 / fromMPList.length + NL
    WMEURMPT.statsCSV += 'Not identified;' + niMP + ';' + niMP * 100 / closedMP + NL
    WMEURMPT.statsCSV += 'Solved;' + soMP + ';' + soMP * 100 / closedMP + NL
    const bestPipeletteList = []
    const bestURCloserList = []
    const bestMPCloserList = []
    for (let i = 0; i < fromURList.length; i++) {
      const ur = fromURList[i]
      if (ur.data.hasComments === true) {
        for (let c = 0; c < ur.data.session.comments.length; c++) {
          const userName = ur.data.session.comments[c].userName
          if (userName === 'Reporter' || userName === 'Unknown') {
            continue
          }
          if (Object.prototype.hasOwnProperty.call(bestPipeletteList, userName)) {
            bestPipeletteList[userName]++
          } else {
            bestPipeletteList[userName] = 1
          }
        }
      }
      if (!ur.data.open) {
        if (Object.prototype.hasOwnProperty.call(bestURCloserList, ur.data.resolvedByName)) {
          bestURCloserList[ur.data.resolvedByName].total++
        } else {
          bestURCloserList[ur.data.resolvedByName] = { total: 1, solved: 0 }
        }
        if (ur.data.resolution !== 1) {
          bestURCloserList[ur.data.resolvedByName].solved++
        }
      }
    }
    for (let i = 0; i < fromMPList.length; i++) {
      const mp = fromMPList[i]
      if (!mp.data.open) {
        if (Object.prototype.hasOwnProperty.call(bestMPCloserList, mp.data.resolvedByName)) {
          bestMPCloserList[mp.data.resolvedByName].total++
        } else {
          bestMPCloserList[mp.data.resolvedByName] = { total: 1, solved: 0 }
        }
        if (mp.data.resolution !== 1) {
          bestMPCloserList[mp.data.resolvedByName].solved++
        }
      }
    }
    const sortablePipelettes = []
    for (const p in bestPipeletteList) {
      if (Object.prototype.hasOwnProperty.call(bestPipeletteList, p)) {
        sortablePipelettes.push([p, bestPipeletteList[p]])
      }
    }
    const sortableURClosers = []
    for (const c in bestURCloserList) {
      if (Object.prototype.hasOwnProperty.call(bestURCloserList, c)) {
        sortableURClosers.push([c, bestURCloserList[c]])
      }
    }
    const sortableMPClosers = []
    for (const c in bestMPCloserList) {
      if (Object.prototype.hasOwnProperty.call(bestMPCloserList, c)) {
        sortableMPClosers.push([c, bestMPCloserList[c]])
      }
    }
    sortablePipelettes.sort(function (a, b) {
      return b[1] - a[1]
    })
    sortableURClosers.sort(function (a, b) {
      return b[1].total - a[1].total
    })
    sortableMPClosers.sort(function (a, b) {
      return b[1].total - a[1].total
    })
    WMEURMPT.statsCSV += 'Bests' + NL
    out += 'Best UR closer:<ol>'
    WMEURMPT.statsCSV += 'UR Closer;count;solved;not identified' + NL
    for (let i = 0; i < 3 && i < sortableURClosers.length; i++) {
      out += '<li>' + sortableURClosers[i][0] + ' (' + sortableURClosers[i][1].total + ' URs closed, ' + sortableURClosers[i][1].solved + ' solved and ' + (sortableURClosers[i][1].total - sortableURClosers[i][1].solved) + ' not identified)</li>'
      WMEURMPT.statsCSV += sortableURClosers[i][0] + ';' + sortableURClosers[i][1].total + ';' + sortableURClosers[i][1].solved + ';' + (sortableURClosers[i][1].total - sortableURClosers[i][1].solved) + NL
    }
    out += '</ol>'
    out += 'Best MP closer:<ol>'
    WMEURMPT.statsCSV += 'MP Closer;count;solved;not identified' + NL
    for (let i = 0; i < 3 && i < sortableMPClosers.length; i++) {
      out += '<li>' + sortableMPClosers[i][0] + ' (' + sortableMPClosers[i][1].total + ' MPs closed, ' + sortableMPClosers[i][1].solved + ' solved and ' + (sortableMPClosers[i][1].total - sortableMPClosers[i][1].solved) + ' not identified)</li>'
      WMEURMPT.statsCSV += sortableMPClosers[i][0] + ';' + sortableMPClosers[i][1].total + ';' + sortableMPClosers[i][1].solved + ';' + (sortableMPClosers[i][1].total - sortableMPClosers[i][1].solved) + NL
    }
    out += '</ol>'
    out += 'Best pipelette:<ol>'
    WMEURMPT.statsCSV += 'Pipelette;Message count' + NL
    for (let i = 0; i < 3 && i < sortablePipelettes.length; i++) {
      out += '<li>' + sortablePipelettes[i][0] + ' (' + sortablePipelettes[i][1] + ' comments)</li>'
      WMEURMPT.statsCSV += sortablePipelettes[i][0] + ';' + sortablePipelettes[i][1] + NL
    }
    out += '</ol>'
    return out
  }
  WMEURMPT.refreshStats = function (fromDate, toDate) {
    WMEURMPT.log('refreshStats from: ', fromDate)
    WMEURMPT.log('refreshStats to: ', toDate)
    const pb = new WMEURMPT.ProgressBar(WMEURMPT.getId('urt-progressBar'))
    if (pb.isShown() === false) {
      pb.update(-1)
      pb.show()
      WMEURMPT.showPBInfo(true)
      WMEURMPT.info('Refreshing stats, please wait...')
      window.setTimeout(WMEURMPT.getFunctionWithArgs(WMEURMPT.refreshStats, [fromDate, toDate]))
      return
    }
    WMEURMPT.statsCSV = ''
    const div = WMEURMPT.getId('urmpt-stats')
    WMEURMPT.removeChildElements(div)

    div.innerHTML = WMEURMPT.convertHtml('<font style="font-size: larger; font-weight: bold;">Statistics</font><hr/>')
    div.innerHTML += WMEURMPT.convertHtml('<div style="display: flex;"><span style="margin: 5px; display: table;" >From: </span><input value="' + fromDate + '" type="text" id="urmpt-stat-from" size="9"/><span style="margin: 5px; display: table;" > to </span><input value="' + toDate + '" type="text" id="urmpt-stat-to" size="9"/><button id="urmpt-stat-refresh" style="display: table; width: 40px; padding: 0px;">OK</button></div><hr/>')
    div.innerHTML += WMEURMPT.convertHtml('<a id="urmpt-stat-export_csv" href="#">Export to CSV</a><hr/>')
    let dateFilteredURList = WMEURMPT.URList
    let dateFilteredMPList = WMEURMPT.MPList
    if (fromDate !== '' && toDate !== '') {
      const df = (new Date(fromDate)).getTime()
      const dt = (new Date(toDate)).getTime()
      dateFilteredURList = WMEURMPT.URList.filter(function (value) {
        return (value.data.resolvedOn != null && value.data.resolvedOn >= df && value.data.resolvedOn <= dt) || (value.data.updatedOn != null && value.data.updatedOn >= df && value.data.updatedOn <= dt) || (value.data.driveDate != null && value.data.driveDate >= df && value.data.driveDate <= dt)
      })
      dateFilteredMPList = WMEURMPT.MPList.filter(function (value) {
        return value.data.resolvedOn != null && value.data.resolvedOn >= df && value.data.resolvedOn <= dt
      })
    }
    div.innerHTML += WMEURMPT.convertHtml('General:<br/><br/>')
    WMEURMPT.statsCSV += 'General' + NL
    div.innerHTML += WMEURMPT.convertHtml(WMEURMPT.computeStats(dateFilteredURList, dateFilteredMPList, fromDate, toDate))
    div.innerHTML += WMEURMPT.convertHtml('<hr/>')
    div.innerHTML += WMEURMPT.convertHtml('You:<br/><br/>')
    const closedURbyMe = dateFilteredURList.filter(function (value) {
      return value.data.resolvedBy === WMEURMPT.me.getID()
    }).length
    const closedMPbyMe = dateFilteredMPList.filter(function (value) {
      return value.data.resolvedBy === WMEURMPT.me.getID()
    }).length
    const niURbyMe = dateFilteredURList.filter(function (value) {
      return value.data.resolvedBy === WMEURMPT.me.getID() && value.data.open === false && value.data.resolution === 1
    }).length
    const soURbyMe = closedURbyMe - niURbyMe
    const niMPbyMe = dateFilteredMPList.filter(function (value) {
      return value.data.resolvedBy === WMEURMPT.me.getID() && value.data.open === false && value.data.resolution === 1
    }).length
    const soMPbyMe = closedMPbyMe - niMPbyMe
    div.innerHTML += WMEURMPT.convertHtml('URs closed: ' + closedURbyMe + ' (' + Math.round(closedURbyMe * 100 / dateFilteredURList.length) + '%)<br/>')
    div.innerHTML += WMEURMPT.convertHtml('&nbsp;&nbsp;Not identified: ' + niURbyMe + ' (' + Math.round(niURbyMe * 100 / closedURbyMe) + '%)<br/>')
    div.innerHTML += WMEURMPT.convertHtml('&nbsp;&nbsp;Solved: ' + soURbyMe + ' (' + Math.round(soURbyMe * 100 / closedURbyMe) + '%)<br/>')
    div.innerHTML += WMEURMPT.convertHtml('MPs closed: ' + closedMPbyMe + ' (' + Math.round(closedMPbyMe * 100 / dateFilteredMPList.length) + '%)<br/>')
    div.innerHTML += WMEURMPT.convertHtml('&nbsp;&nbsp;Not identified: ' + niMPbyMe + ' (' + Math.round(niMPbyMe * 100 / closedMPbyMe) + '%)<br/>')
    div.innerHTML += WMEURMPT.convertHtml('&nbsp;&nbsp;Solved: ' + soMPbyMe + ' (' + Math.round(soMPbyMe * 100 / closedMPbyMe) + '%)<br/>')
    div.innerHTML += WMEURMPT.convertHtml('<hr/>')
    div.innerHTML += WMEURMPT.convertHtml('Per area:<br/><br/>')
    div.innerHTML += WMEURMPT.convertHtml('<ul>')
    WMEURMPT.statsCSV += 'You' + NL
    WMEURMPT.statsCSV += 'UR;Count;Percent' + NL
    WMEURMPT.statsCSV += 'Closed;' + closedURbyMe + ';' + closedURbyMe * 100 / dateFilteredURList.length + NL
    WMEURMPT.statsCSV += 'Not identified;' + niURbyMe + ';' + niURbyMe * 100 / closedURbyMe + NL
    WMEURMPT.statsCSV += 'Solved;' + soURbyMe + ';' + soURbyMe * 100 / closedURbyMe + NL
    WMEURMPT.statsCSV += 'MP;Count;Percent' + NL
    WMEURMPT.statsCSV += 'Closed;' + closedMPbyMe + ';' + closedMPbyMe * 100 / dateFilteredMPList.length + NL
    WMEURMPT.statsCSV += 'Not identified;' + niMPbyMe + ';' + niMPbyMe * 100 / closedMPbyMe + NL
    WMEURMPT.statsCSV += 'Solved;' + soMPbyMe + ';' + soMPbyMe * 100 / closedMPbyMe + NL
    WMEURMPT.statsCSV += 'Your drive area' + NL
    let fromURList = dateFilteredURList.filter(function (value) {
      return WMEURMPT.isInsideDriveArea(value.lonlat.lon, value.lonlat.lat)
    })
    let fromMPList = dateFilteredMPList.filter(function (value) {
      return WMEURMPT.isInsideDriveArea(value.lonlat.lon, value.lonlat.lat)
    })
    div.innerHTML += WMEURMPT.convertHtml('<li>Your drive area<br/>' + WMEURMPT.computeStats(fromURList, fromMPList, fromDate, toDate) + '</li>')
    if (WMEURMPT.uam) {
      WMEURMPT.statsCSV += 'Your managed area' + NL
      fromURList = dateFilteredURList.filter(function (value) {
        return WMEURMPT.isInsideManagedArea(value.lonlat.lon, value.lonlat.lat)
      })
      fromMPList = dateFilteredMPList.filter(function (value) {
        return WMEURMPT.isInsideManagedArea(value.lonlat.lon, value.lonlat.lat)
      })
      div.innerHTML += WMEURMPT.convertHtml('<li>Your managed area<br/>' + WMEURMPT.computeStats(fromURList, fromMPList, fromDate, toDate) + '</li>')
    }
    for (let a = 0; a < WMEURMPT.areaList.country.length; a++) {
      WMEURMPT.statsCSV += WMEURMPT.areaList.country[a].name + NL
      fromURList = dateFilteredURList.filter(function (value) {
        return WMEURMPT.areaList.country[a].isInside(value.lonlat)
      })
      fromMPList = dateFilteredMPList.filter(function (value) {
        return WMEURMPT.areaList.country[a].isInside(value.lonlat)
      })
      div.innerHTML += WMEURMPT.convertHtml('<li>' + WMEURMPT.areaList.country[a].name + '<br/>' + WMEURMPT.computeStats(fromURList, fromMPList, fromDate, toDate) + '</li>')
    }
    for (let a = 0; a < WMEURMPT.areaList.custom.length; a++) {
      WMEURMPT.statsCSV += WMEURMPT.areaList.custom[a].name + NL
      fromURList = dateFilteredURList.filter(function (value) {
        return WMEURMPT.areaList.custom[a].isInside(value.lonlat)
      })
      fromMPList = dateFilteredMPList.filter(function (value) {
        return WMEURMPT.areaList.custom[a].isInside(value.lonlat)
      })
      div.innerHTML += WMEURMPT.convertHtml('<li>' + WMEURMPT.areaList.custom[a].name + '<br/>' + WMEURMPT.computeStats(fromURList, fromMPList, fromDate, toDate) + '</li>')
    }
    div.innerHTML += WMEURMPT.convertHtml('</ul>')
    WMEURMPT.showPBInfo(false)
    pb.hide()
    pb.update(0)
    WMEURMPT.info()
    window.setTimeout(WMEURMPT.setupStatHandlers)
  }

  WMEURMPT.setupStatHandlers = function () {
    if (typeof $.fn.datepicker !== 'undefined') {
      $('#urmpt-stat-from,#urmpt-stat-to').datepicker()
    } else if (typeof $.fn.daterangepicker !== 'undefined') {
      $('#urmpt-stat-from,#urmpt-stat-to').daterangepicker({ singleDatePicker: !0, locale: { format: 'YYYY-MM-DD' } })
    }
    WMEURMPT.getId('urmpt-stat-refresh').onclick = function () {
      const dateFrom = WMEURMPT.getId('urmpt-stat-from').value
      const dateTo = WMEURMPT.getId('urmpt-stat-to').value
      WMEURMPT.refreshStats(dateFrom, dateTo)
    }
    WMEURMPT.getId('urmpt-stat-export_csv').onclick = WMEURMPT.exportStatsToCSV
  }

  WMEURMPT.exportStatsToCSV = function () {
    this.setAttribute('download', 'URMPT_Stats_' + (new Date()).toISOString().substr(0, 10) + '_' + WMEURMPT.me.getUsername() + '.csv')
    this.href = 'data:application/octet-stream;charset=utf-8;base64,' + btoa(WMEURMPT.statsCSV)
  }

  WMEURMPT.connectStatHandler = function () {
    WMEURMPT.getId('urmp-tabstitle-stat').onclick = WMEURMPT.getFunctionWithArgs(WMEURMPT.refreshStats, ['', ''])
  }

  WMEURMPT.exportURMPs = function (t, button) {
    button.setAttribute('download', t + 's.bbcode.txt')
    let data = ''
    let displayedCount = 0

    let src = null
    let filterFunc = null
    let limit = -1
    let typeFunc = null

    switch (t) {
      case 'UR':
      {
        src = WMEURMPT.URList
        filterFunc = WMEURMPT.isURFiltered
        limit = WMEURMPT.currentURLimitTo
        typeFunc = WMEURMPT.getFullURTypeFromType
        break
      }
      case 'MP':
      {
        src = WMEURMPT.MPList
        filterFunc = WMEURMPT.isMPFiltered
        limit = WMEURMPT.currentMPLimitTo
        typeFunc = WMEURMPT.getFullMPTypeFromType
        break
      }
    }
    for (let i = 0; i < src.length; i++) {
      if (WMEURMPT.getId(t.toLowerCase() + 't-checkbox-filterHideLimitTo').checked) {
        if (displayedCount >= limit) {
          break
        }
      }
      if (filterFunc(src[i])) {
        continue
      }
      displayedCount++
      const number = t === 'UR' ? WMEURMPT.getDuration(src[i].data.driveDate) : src[i].data.weight
      const type = typeFunc(t === 'UR' ? src[i].data.type : src[i].data.subType)
      const url = location.protocol + '//' + location.host + location.pathname + '?lon=' + src[i].lonlat.lon + '&lat=' + src[i].lonlat.lat + '&zoom=5' + (t === 'UR' ? '&mapUpdateRequest=' : '&mapProblem=') + src[i].id
      data += '[url=' + url + ']' + (t === 'MP' ? 'Severity: ' : '') + number + (t === 'UR' ? ' days' : '') + ' ' + ' | ' + type + (t === 'UR' ? Object.prototype.hasOwnProperty.call(src[i].data, 'description') && src[i].data.description ? ' | ' + src[i].data.description : ' | N/A' : '') + '[/url]' + NL
    }
    button.href = 'data:text/plain;base64,' + btoa(unescape(encodeURIComponent(data)))
  }

  WMEURMPT.exportCSV_URMPs = function (t, button) {
    const now = new Date()
    const monthStr = now.getMonth() + 1
    const dayStr = now.getDate()
    const nowStr = now.getFullYear() + '-' + ((monthStr < 10 ? '0' : '') + monthStr) + ((dayStr < 10 ? '-0' : '-') + dayStr) + '_' + now.getHours() + '-' + now.getMinutes()
    button.setAttribute('download', t + 's_' + nowStr + '.csv')
    let data = ''
    let displayedCount = 0
    data += 'date opened,type,age,visited,description,num comments,date updated,updated by,updated age,resolved,url,id' + NL

    let src = null
    let filterFunc = null
    let limit = -1
    let typeFunc = null

    switch (t) {
      case 'UR':
      {
        src = WMEURMPT.URList
        filterFunc = WMEURMPT.isURFiltered
        limit = WMEURMPT.currentURLimitTo
        typeFunc = WMEURMPT.getFullURTypeFromType
        break
      }
      case 'MP':
      {
        src = WMEURMPT.MPList
        filterFunc = WMEURMPT.isMPFiltered
        limit = WMEURMPT.currentMPLimitTo
        typeFunc = WMEURMPT.getFullMPTypeFromType
        break
      }
    }
    for (let i = 0; i < src.length; i++) {
      if (WMEURMPT.getId(t.toLowerCase() + 't-checkbox-filterHideLimitTo').checked) {
        if (displayedCount >= limit) {
          break
        }
      }
      if (filterFunc(src[i])) {
        continue
      }
      displayedCount++
      const number = t === 'UR' ? WMEURMPT.getDuration(src[i].data.driveDate) : src[i].data.weight
      const type = typeFunc(t === 'UR' ? src[i].data.type : src[i].data.subType)
      const commentCount = src[i].data.session.comments.length
      let updatedBy = ''
      if (commentCount > 0) {
        const m = commentCount - 1
        updatedBy = src[i].data.session.comments[m].userName
      }
      const updatedDate = (src[i].data.updatedOn === null ? '' : ((new Date(src[i].data.updatedOn)).toLocaleString('sv-SE')))
      let updatedDays = (src[i].data.updatedOn === null ? 0 : ((new Date()).getTime() - (new Date(src[i].data.updatedOn).getTime())))
      updatedDays = updatedDays / (1000 * 60 * 60 * 24)
      const updatedAge = Math.round(updatedDays)
      const url = location.protocol + '//' + location.host + location.pathname + '?lon=' + src[i].lonlat.lon + '&lat=' + src[i].lonlat.lat + '&zoom=5' + (t === 'UR' ? '&mapUpdateRequest=' : '&mapProblem=') + src[i].id
      data += '"' + src[i].data.localDriveTime + '","' + type + '","' + number + '","' + src[i].alreadyVisited + '","' + (t === 'UR' ? Object.prototype.hasOwnProperty.call(src[i].data, 'description') && src[i].data.description ? src[i].data.description : 'N/A' : '') + '","' + commentCount + '","' + updatedDate + '","' + updatedBy + '","' + updatedAge + '","' + (src[i].data.resolvedOn === null ? 'N' : 'Y') + '","' + url + '","' + src[i].id + '"' + NL
    }
    button.href = 'data:text/plain;base64,' + btoa(unescape(encodeURIComponent(data)))
  }

  WMEURMPT.exportKML_URMPs = function (t, button, start) {
    let kml = ''

    let src = null
    let filterFunc = null
    let typeFunc = null

    let finished = true
    let displayedCount = 0
    const data = {}

    switch (t) {
      case 'UR':
      {
        src = WMEURMPT.URList
        filterFunc = WMEURMPT.isURFiltered
        typeFunc = WMEURMPT.getFullURTypeFromType
        break
      }
      case 'MP':
      {
        src = WMEURMPT.MPList
        filterFunc = WMEURMPT.isMPFiltered
        typeFunc = WMEURMPT.getFullMPTypeFromType
        break
      }
    }

    for (let i = start; i < src.length; i++) {
      if (displayedCount === 2500) {
        start = i
        finished = false
        break
      }
      if (filterFunc(src[i])) {
        continue
      }
      displayedCount++
      const number = t === 'UR' ? WMEURMPT.getDuration(src[i].data.driveDate) : src[i].data.weight
      const type = typeFunc(t === 'UR' ? src[i].data.type : src[i].data.subType)
      let color = 'green'
      if (src[i].data.open) {
        if (t === 'UR') {
          if (number < 15) {
            color = 'yellow'
          } else if (number < 30) {
            color = 'orange'
          } else {
            color = 'red'
          }
        } else {
          if (number < 51) {
            color = 'yellow'
          } else if (number < 100) {
            color = 'orange'
          } else {
            color = 'red'
          }
        }
      }
      if (Object.prototype.hasOwnProperty.call(data, type) === false) {
        data[type] = []
      }
      data[type].push({ lonlat: src[i].lonlat, color })
    }
    kml = '<?xml version="1.0" encoding="UTF-8"?><kml xmlns="http://www.opengis.net/kml/2.2" xmlns:gx="http://www.google.com/kml/ext/2.2" xmlns:kml="http://www.opengis.net/kml/2.2" xmlns:atom="http://www.w3.org/2005/Atom"><Document><name>' + t + 's</name><Style id="sn_red"><IconStyle><color>7f0000ff</color><scale>0.5</scale><Icon><href>http://maps.google.com/mapfiles/kml/shapes/shaded_dot.png</href></Icon></IconStyle><LabelStyle><scale>0</scale></LabelStyle><ListStyle></ListStyle></Style><Style id="sh_red"><IconStyle><color>7f0000ff</color><scale>0.6</scale><Icon><href>http://maps.google.com/mapfiles/kml/shapes/shaded_dot.png</href></Icon></IconStyle><LabelStyle><scale>0</scale></LabelStyle><ListStyle></ListStyle></Style><StyleMap id="msn_red"><Pair><key>normal</key><styleUrl>#sn_red</styleUrl></Pair><Pair><key>highlight</key><styleUrl>#sh_red</styleUrl></Pair></StyleMap><Style id="sn_orange"><IconStyle><color>7f0080ff</color><scale>0.5</scale><Icon><href>http://maps.google.com/mapfiles/kml/shapes/shaded_dot.png</href></Icon></IconStyle><LabelStyle><scale>0</scale></LabelStyle><ListStyle></ListStyle></Style><Style id="sh_orange"><IconStyle><color>7f0080ff</color><scale>0.6</scale><Icon><href>http://maps.google.com/mapfiles/kml/shapes/shaded_dot.png</href></Icon></IconStyle><LabelStyle><scale>0</scale></LabelStyle><ListStyle></ListStyle></Style><StyleMap id="msn_orange"><Pair><key>normal</key><styleUrl>#sn_orange</styleUrl></Pair><Pair><key>highlight</key><styleUrl>#sh_orange</styleUrl></Pair></StyleMap><Style id="sn_yellow"><IconStyle><color>7f00ffff</color><scale>0.5</scale><Icon><href>http://maps.google.com/mapfiles/kml/shapes/shaded_dot.png</href></Icon></IconStyle><LabelStyle><scale>0</scale></LabelStyle><ListStyle></ListStyle></Style><Style id="sh_yellow"><IconStyle><color>7f00ffff</color><scale>0.6</scale><Icon><href>http://maps.google.com/mapfiles/kml/shapes/shaded_dot.png</href></Icon></IconStyle><LabelStyle><scale>0</scale></LabelStyle><ListStyle></ListStyle></Style><StyleMap id="msn_yellow"><Pair><key>normal</key><styleUrl>#sn_yellow</styleUrl></Pair><Pair><key>highlight</key><styleUrl>#sh_yellow</styleUrl></Pair></StyleMap><Style id="sn_green"><IconStyle><color>7f00ff00</color><scale>0.5</scale><Icon><href>http://maps.google.com/mapfiles/kml/shapes/shaded_dot.png</href></Icon></IconStyle><LabelStyle><scale>0</scale></LabelStyle><ListStyle></ListStyle></Style><Style id="sh_green"><IconStyle><color>7f00ff00</color><scale>0.6</scale><Icon><href>http://maps.google.com/mapfiles/kml/shapes/shaded_dot.png</href></Icon></IconStyle><LabelStyle><scale>0</scale></LabelStyle><ListStyle></ListStyle></Style><StyleMap id="msn_green"><Pair><key>normal</key><styleUrl>#sn_green</styleUrl></Pair><Pair><key>highlight</key><styleUrl>#sh_green</styleUrl></Pair></StyleMap>'
    for (const type in data) {
      kml += '<Folder><name>'
      kml += type
      kml += '</name><open>0</open>'
      data[type].forEach(function (r) {
        kml += '<Placemark><name></name><description></description><LookAt><longitude>' + r.lonlat.lon + '</longitude><latitude>' + r.lonlat.lat + '</latitude><altitude>0</altitude><heading>0</heading><tilt>0</tilt><range>1000.000000</range><gx:altitudeMode>relativeToSeaFloor</gx:altitudeMode></LookAt><styleUrl>#msn_' + r.color + '</styleUrl><Point><gx:drawOrder>1</gx:drawOrder><coordinates>' + r.lonlat.lon + ',' + r.lonlat.lat + ',0</coordinates></Point></Placemark>'
      })
      kml += '</Folder>'
    }
    kml += '</Document></kml>'
    const element = document.createElement('a')
    element.style.display = 'none'
    element.setAttribute('href', encodeURI('data:text/plain,' + kml))
    element.setAttribute('download', t + 's_' + start + '.kml')
    document.body.appendChild(element)
    element.click()
    document.body.removeChild(element)
    if (finished === false) {
      window.setTimeout(function () {
        WMEURMPT.exportKML_URMPs(t, button, start)
      })
    }
  }

  WMEURMPT.initialiseURT = function () {
    WMEURMPT.initManagedArea()
    let content = ''
    const addon = WMEURMPT.createElement('section', 'urt-addon')
    const divpbi = WMEURMPT.createElement('div', 'urt-progressBarInfo')
    divpbi.className = 'urt-progressBarInfo'
    let elt = WMEURMPT.createElement('div', 'urt-progressBar')
    elt.style.width = '100%'
    elt.style.display = 'none'
    elt.innerHTML = WMEURMPT.convertHtml('<div class="urt-progressBarBG"></div><span class="urt-progressBarFG">100%</span>')
    divpbi.appendChild(elt)
    elt = WMEURMPT.createElement('div', 'urt-info')
    divpbi.appendChild(elt)
    addon.appendChild(divpbi)
    const section = WMEURMPT.createElement('p', 'urt-main-title')
    section.style.paddingTop = '0px'
    section.style.marginTop = '-15px'
    section.style.textIndent = '8px'
    const title = '<b><a target="_blank" href="https://greasyfork.org/fr/scripts/368141-wme-ur-mp-tracking"><u>UR-MP Tracking</u></a> <a target="_blank" href="https://www.waze.com/forum/viewtopic.php?f=68&t=91786">Fr</a> <a target="_blank" href="https://www.waze.com/forum/viewtopic.php?f=819&t=125216">En</a> </b> v' + WMEURMPT.urmpt_version + '<span style="padding-left: 20px;"><a href="#" id="urmpt-onoff"><img class="urt-chkbox" src="data:image/png;base64,' + (WMEURMPT.isEnabled
      ? WMEURMPT.icon_checked
      : WMEURMPT.icon_unchecked) + '" /></a></span>'
    section.innerHTML = WMEURMPT.convertHtml(title)
    if (WMEURMPT.displayLegend) {
      section.innerHTML += WMEURMPT.convertHtml('<img id="urt-close-legend" style="display: block; position: relative; left: 5px; top: 10px; float: right; z-index: 99; width: 16px; height: 16px;" src="data:image/png;base64,' + WMEURMPT.icon_delete + '" /><div id="urt-legend" ><table class="urt-table"><tr><td class="urt-bg-selected">Last visited</td><td>Visited</td></tr><tr><td class="urt-bg-ifollow">I follow</td><td class="urt-bg-highlighted">Never visited</td></tr></table></div>')
    }
    addon.appendChild(section)
    const quickOptions = WMEURMPT.createElement('span', 'urmpt-qoptions')
    let qohtml = ''
    qohtml = '<font style="font-size: smaller; font-weight: 600;">Quick options:</font><hr style="margin: 0px;" />'
    qohtml += '<table style="border: 0px; width: 100%;"><tr>'
    qohtml += '<td style="width: 50%;">'
    qohtml += '<a href="#" id="urmpt-donoff"><img class="urt-chkbox" src="data:image/png;base64,' + (WMEURMPT.isComputeDistances ? WMEURMPT.icon_checked : WMEURMPT.icon_unchecked) + '" /></a>Distances<br/>'
    qohtml += '<a href="#" id="urmpt-asonoff"><img class="urt-chkbox" src="data:image/png;base64,' + (WMEURMPT.isAutoScan ? WMEURMPT.icon_checked : WMEURMPT.icon_unchecked) + '" /></a>Auto scan'
    qohtml += '</td><td>'
    qohtml += '<a href="#" id="urmpt-suronoff"><img class="urt-chkbox" src="data:image/png;base64,' + (WMEURMPT.scanUR ? WMEURMPT.icon_checked : WMEURMPT.icon_unchecked) + '" /></a>Scan UR<br/>'
    qohtml += '<a href="#" id="urmpt-smponoff"><img class="urt-chkbox" src="data:image/png;base64,' + (WMEURMPT.scanMP ? WMEURMPT.icon_checked : WMEURMPT.icon_unchecked) + '" /></a>Scan MP<br/>'
    qohtml += '<a href="#" id="urmpt-smconoff"><img class="urt-chkbox" src="data:image/png;base64,' + (WMEURMPT.scanMC ? WMEURMPT.icon_checked : WMEURMPT.icon_unchecked) + '" /></a>Scan MC<br/>'
    qohtml += '<a href="#" id="urmpt-spuronoff"><img class="urt-chkbox" src="data:image/png;base64,' + (WMEURMPT.scanPUR ? WMEURMPT.icon_checked : WMEURMPT.icon_unchecked) + '" /></a>Scan PUR'
    qohtml += '</td>'
    qohtml += '</tr></table>'
    quickOptions.innerHTML = WMEURMPT.convertHtml(qohtml)
    addon.appendChild(quickOptions)
    const generalMenu = WMEURMPT.createElement('center')
    generalMenu.style.marginBottom = '10px'
    addon.appendChild(generalMenu)
    const scanGroup = WMEURMPT.createElement('div', 'urt-a-scanGroup')
    generalMenu.appendChild(scanGroup)
    const urmpTabs = WMEURMPT.createElement('ul', 'urmp-tabs')
    addon.appendChild(urmpTabs)
    urmpTabs.className = 'nav nav-tabs'
    urmpTabs.innerHTML = WMEURMPT.convertHtml('<li class="active" style="width: 13.75%; text-align: center; height: 30px;"><a id="urmp-tabstitle-ur" style="height: 30px;" href="#urmp-tabs-ur" data-toggle="tab">UR</a></li>')
    urmpTabs.innerHTML += WMEURMPT.convertHtml('<li class="" style="width: 13.75%; text-align: center; height: 30px;"><a id="urmp-tabstitle-mp" style="height: 30px;" href="#urmp-tabs-mp" data-toggle="tab">MP</a></li>')
    urmpTabs.innerHTML += WMEURMPT.convertHtml('<li class="" style="width: 13.75%; text-align: center; height: 30px;"><a id="urmp-tabstitle-mc" style="height: 30px;" href="#urmp-tabs-mc" data-toggle="tab">MC</a></li>')
    urmpTabs.innerHTML += WMEURMPT.convertHtml('<li class="" style="width: 13.75%; text-align: center; height: 30px;"><a id="urmp-tabstitle-pur" style="height: 30px;" href="#urmp-tabs-pur" data-toggle="tab">PUR</a></li>')
    urmpTabs.innerHTML += WMEURMPT.convertHtml('<li class="" style="width: 13.75%; text-align: center; height: 30px;"><a class="fa fa-bar-chart icon-bar-chart" id="urmp-tabstitle-stat" style="height: 30px;" href="#urmp-tabs-os" data-toggle="tab"></a></li>')
    urmpTabs.innerHTML += WMEURMPT.convertHtml('<li class="" style="width: 13.75%; text-align: center; height: 30px;"><a class="w-icon-2x w-icon w-icon-pencil" style="font-size: 1.5em; height: 30px;" href="#urmp-tabs-areas" data-toggle="tab"></a></li>')
    urmpTabs.innerHTML += WMEURMPT.convertHtml('<li class="" style="width: 13.75%; text-align: center; height: 30px;"><a class="w-icon-2x w-icon w-icon-settings" style="font-size: 1.5em; height: 30px;" href="#urmp-tabs-settings" data-toggle="tab"></a></li>')
    window.setTimeout(WMEURMPT.connectStatHandler)
    window.setTimeout(WMEURMPT.connectURTabHandler)
    window.setTimeout(WMEURMPT.connectMPTabHandler)
    window.setTimeout(WMEURMPT.connectMCTabHandler)
    window.setTimeout(WMEURMPT.connectPURTabHandler)
    const urmpTabContent = WMEURMPT.createElement('div', 'urmpt-tab-content')
    urmpTabContent.className = 'tab-content'
    urmpTabContent.style.paddingBottom = '10px'
    urmpTabContent.style.paddingTop = '0px'
    urmpTabContent.style.paddingLeft = '5px'
    urmpTabContent.style.paddingRight = '5px'
    addon.appendChild(urmpTabContent)
    const urTabPane = WMEURMPT.createElement('section', 'urmp-tabs-ur')
    urTabPane.className = 'tab-pane active'
    urTabPane.style.paddingLeft = '0px'
    urTabPane.style.paddingRight = '0px'
    urmpTabContent.appendChild(urTabPane)
    const urMenu = WMEURMPT.createElement('center')
    urTabPane.appendChild(urMenu)
    elt = WMEURMPT.createElement('a', 'urt-a-markallvisited')
    elt.innerHTML = WMEURMPT.convertHtml('Mark all as visited')
    elt.href = '#'
    elt.onclick = WMEURMPT.markAllURAsVisited
    urMenu.appendChild(elt)
    elt = WMEURMPT.createElement('span')
    elt.innerHTML = WMEURMPT.convertHtml('|')
    urMenu.appendChild(elt)
    elt = WMEURMPT.createElement('a', 'urt-a-clearAll')
    elt.innerHTML = WMEURMPT.convertHtml('Clear all')
    elt.href = '#'
    elt.onclick = WMEURMPT.clearAllUR
    urMenu.appendChild(elt)
    elt = WMEURMPT.createElement('span')
    elt.innerHTML = WMEURMPT.convertHtml('|')
    urMenu.appendChild(elt)
    elt = WMEURMPT.createElement('a', 'urt-a-export')
    elt.href = '#'
    elt.innerHTML = WMEURMPT.convertHtml('<img src="data:image/png;base64,' + WMEURMPT.icon_export + '" width="14px" height="14px" alt="Export BBCode" title="Export BBCode" />')
    elt.onclick = function () {
      const that = this
      WMEURMPT.exportURMPs('UR', that)
    }
    urMenu.appendChild(elt)
    elt = WMEURMPT.createElement('span')
    elt.innerHTML = WMEURMPT.convertHtml('|')
    urMenu.appendChild(elt)
    elt = WMEURMPT.createElement('a', 'urt-a-export-csv')
    elt.href = '#'
    elt.innerHTML = WMEURMPT.convertHtml('<img src="data:image/png;base64,' + WMEURMPT.icon_csv + '" width="14px" height="14px" alt="Export CSV" title="Export CSV" />')
    elt.onclick = function () {
      const that = this
      WMEURMPT.exportCSV_URMPs('UR', that)
    }
    urMenu.appendChild(elt)
    elt = WMEURMPT.createElement('span')
    elt.innerHTML = WMEURMPT.convertHtml('|')
    urMenu.appendChild(elt)
    elt = WMEURMPT.createElement('a', 'urt-a-export-kml')
    elt.href = '#'
    elt.innerHTML = WMEURMPT.convertHtml('<img src="data:image/png;base64,' + WMEURMPT.icon_ge + '" height="14px" alt="Export KML" title="Export KML" />')
    elt.onclick = function () {
      const that = this
      WMEURMPT.exportKML_URMPs('UR', that, 0)
      return false
    }
    urMenu.appendChild(elt)
    elt = WMEURMPT.createElement('div')
    content = '<ul class="urt-filter-list">'
    content += '<li><input type="checkbox" id="urt-checkbox-filterInvert"><b>Invert filters</b></li>'
    content += '<li title="Show URs I have already commented"><input type="checkbox" id="urt-checkbox-filterHideWithoutCommentFromMe"> Hide without comment from me</li>'
    content += '<li title="Show URs with last comment from Reporter"><input type="checkbox" id="urt-checkbox-filterHideLastCommentFromEditor"> Hide last comment from an editor</li>'
    content += '<li title="Show only URs from 0 to n comments"><input type="checkbox" id="urt-checkbox-filterHideWithCommentCount"> Hide with more than <input size="2" maxlength="2" type="text" id="urt-filterHideWithCommentCount" value="' + WMEURMPT.currentURCommentsCount + '"></input> comment(s)</li>'
    content += '<li title="Show URs with unread comment(s)"><input type="checkbox" id="urt-checkbox-filterHideNoNewComment"> Hide no new comment</li>'
    content += '<li title="Show URs in my drive areas"><input type="checkbox" id="urt-checkbox-filterHideOutOfMyDriveArea"> Hide out of my drive area</li>'
    if (WMEURMPT.uam) {
      content += '<li title="Show URs in my managed areas"><input type="checkbox" id="urt-checkbox-filterHideOutOfMyManagedArea"> Hide out of my managed area</li>'
    }
    content += '<li title="Show URs I have never seen"><input type="checkbox" id="urt-checkbox-filterHideVisited"> Hide visited</li>'
    if (WMEURMPT.ul >= WMEURMPT.rl4cp) {
      content += '<li title="Show only pendings URs"><input type="checkbox" id="urt-checkbox-filterHideClosed"> Hide closed</li>'
    }
    content += '<li title="Show white listed URs"><input type="checkbox" id="urt-checkbox-filterHideBlacklisted"> Hide black listed</li>'
    content += '<li title="Show black listed URs"><input type="checkbox" id="urt-checkbox-filterHideWhitelisted"> Hide white listed</li>'
    content += '<li title="Show all but General Error"><input type="checkbox" id="urt-checkbox-filterHideGE"> Hide General Error</li>'
    content += '<li title="Show UR if description contains keyword"><input type="checkbox" id="urt-checkbox-filterHideNotKW"> Description keyword: <input type="text" id="urt-filterKW" value="' + WMEURMPT.currentURKeyWord + '"></input></li>'
    content += '<li title="Show only nth first URs"><input type="checkbox" id="urt-checkbox-filterHideLimitTo"> Limit to: <input type="text" id="urt-filterLimitTo" value="' + WMEURMPT.currentURLimitTo + '"></input></li>'
    content += '<li title="Show tagged URs"><input type="checkbox" id="urt-checkbox-filterHideTagged"> Hide tagged</li>'
    content += '<li title="Show only one type"><input type="checkbox" id="urt-checkbox-filterHideOnlyType"> Hide all but: <select style="height: 25px" id="urt-filterOnlyType">'
    const URTypes = [6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 18, 19, 21, 22, 23]
    for (let i = 0; i < URTypes.length; i++) {
      content += '<option value="' + URTypes[i] + '"' + (WMEURMPT.currentUROnlyType === URTypes[i] ? ' selected' : '') + '>' + WMEURMPT.getFullURTypeFromType(URTypes[i]) + '</option>'
    }
    content += '</select></li>'
    content += '<li title="Show only inside area"><input type="checkbox" id="urt-checkbox-filterHideOnlyArea"> Hide all but: <select style="height: 25px" id="urt-filterOnlyArea">'
    content += '</select></li>'
    content += '</ul>'
    urTabPane.appendChild(elt)
    let panel = new WMEURMPT.PopupPannel('FilterUR', '100%', '100%', '#93c4d3')
    panel.setTriggerInnerHTML('Filters')
    panel.setContentsInnerHTML(content)
    panel.installInside(elt)
    elt = WMEURMPT.createElement('div', 'urt-list')
    urTabPane.appendChild(elt)
    const mpTabPane = WMEURMPT.createElement('section', 'urmp-tabs-mp')
    mpTabPane.className = 'tab-pane'
    mpTabPane.style.paddingLeft = '0px'
    mpTabPane.style.paddingRight = '35px'
    urmpTabContent.appendChild(mpTabPane)
    const mpMenu = WMEURMPT.createElement('center')
    mpTabPane.appendChild(mpMenu)
    elt = WMEURMPT.createElement('a', 'mpt-a-markallvisited')
    elt.innerHTML = WMEURMPT.convertHtml('Mark all as visited')
    elt.href = '#'
    elt.onclick = WMEURMPT.markAllMPAsVisited
    mpMenu.appendChild(elt)
    elt = WMEURMPT.createElement('span')
    elt.innerHTML = WMEURMPT.convertHtml('|')
    mpMenu.appendChild(elt)
    elt = WMEURMPT.createElement('a', 'mpt-a-clearAll')
    elt.innerHTML = WMEURMPT.convertHtml('Clear all')
    elt.href = '#'
    elt.onclick = WMEURMPT.clearAllMP
    mpMenu.appendChild(elt)
    elt = WMEURMPT.createElement('span')
    elt.innerHTML = WMEURMPT.convertHtml('|')
    mpMenu.appendChild(elt)
    elt = WMEURMPT.createElement('a', 'mpt-a-export')
    elt.href = '#'
    elt.innerHTML = WMEURMPT.convertHtml('<img src="data:image/png;base64,' + WMEURMPT.icon_export + '" width="14px" height="14px" alt="Export BBCode" title="Export BBCode" />')
    elt.onclick = function () {
      const that = this
      WMEURMPT.exportURMPs('MP', that)
    }
    mpMenu.appendChild(elt)
    elt = WMEURMPT.createElement('span')
    elt.innerHTML = WMEURMPT.convertHtml('|')
    mpMenu.appendChild(elt)
    elt = WMEURMPT.createElement('a', 'urt-a-export-csv')
    elt.href = '#'
    elt.innerHTML = WMEURMPT.convertHtml('<img src="data:image/png;base64,' + WMEURMPT.icon_csv + '" width="14px" height="14px" alt="Export CSV" title="Export CSV" />')
    elt.onclick = function () {
      const that = this
      WMEURMPT.exportCSV_URMPs('MP', that)
    }
    mpMenu.appendChild(elt)
    elt = WMEURMPT.createElement('span')
    elt.innerHTML = WMEURMPT.convertHtml('|')
    mpMenu.appendChild(elt)
    elt = WMEURMPT.createElement('a', 'mpt-a-export-kml')
    elt.href = '#'
    elt.innerHTML = WMEURMPT.convertHtml('<img src="data:image/png;base64,' + WMEURMPT.icon_ge + '" height="14px" alt="Export KML" title="Export KML" />')
    elt.onclick = function () {
      const that = this
      WMEURMPT.exportKML_URMPs('MP', that, 0)
      return false
    }
    mpMenu.appendChild(elt)
    elt = WMEURMPT.createElement('div')
    content = '<ul class="urt-filter-list">'
    content += '<li title="Show MPs in my drive areas"><input type="checkbox" id="mpt-checkbox-filterHideOutOfMyDriveArea"> Hide out of my drive area</li>'
    if (WMEURMPT.uam) {
      content += '<li title="Show MPs in my managed areas"><input type="checkbox" id="mpt-checkbox-filterHideOutOfMyManagedArea"> Hide out of my managed area</li>'
    }
    content += '<li title="Show MPs I have never seen"><input type="checkbox" id="mpt-checkbox-filterHideVisited"> Hide visited</li>'
    if (WMEURMPT.ul >= WMEURMPT.rl4cp) {
      content += '<li title="Show only pendings MPs"><input type="checkbox" id="mpt-checkbox-filterHideClosed"> Hide closed</li>'
    }
    content += '<li title="Show white listed MPs"><input type="checkbox" id="mpt-checkbox-filterHideBlacklisted"> Hide black listed</li>'
    content += '<li title="Show black listed MPs"><input type="checkbox" id="mpt-checkbox-filterHideWhitelisted"> Hide white listed</li>'
    content += '<li title="Show only nth first MPs"><input type="checkbox" id="mpt-checkbox-filterHideLimitTo"> Limit to: <input type="text" id="mpt-filterLimitTo" value="' + WMEURMPT.currentMPLimitTo + '"></input></li>'
    content += '<li title="Show only one type"><input type="checkbox" id="mpt-checkbox-filterHideOnlyType"> Hide all but: <select style="height: 25px" id="mpt-filterOnlyType">'
    const MPTypes = [1, 2, 3, 5, 6, 7, 8, 10, 11, 12, 13, 14, 15, 16, 17, 19, 20, 21, 22, 23, 50, 51, 52, 53, 70, 71, 101, 102, 103, 104, 105, 106, 200, 300]
    for (let i = 0; i < MPTypes.length; i++) {
      content += '<option value="' + MPTypes[i] + '"' + (WMEURMPT.currentMPOnlyType === MPTypes[i] ? ' selected' : '') + '>' + WMEURMPT.getFullMPTypeFromType(MPTypes[i]) + '</option>'
    }
    content += '</select></li>'
    content += '<li title="Show only one area"><input type="checkbox" id="mpt-checkbox-filterHideOnlyArea"> Hide all but: <select style="height: 25px" id="mpt-filterOnlyArea">'
    content += '</select></li>'
    content += '</ul>'
    mpTabPane.appendChild(elt)
    const panelMP = new WMEURMPT.PopupPannel('FilterMP', '100%', '100%', '#93c4d3')
    panelMP.setTriggerInnerHTML('Filters')
    panelMP.setContentsInnerHTML(content)
    panelMP.installInside(elt)
    elt = WMEURMPT.createElement('div', 'mpt-list')
    mpTabPane.appendChild(elt)
    const mcTabPane = WMEURMPT.createElement('section', 'urmp-tabs-mc')
    mcTabPane.className = 'tab-pane'
    mcTabPane.style.paddingLeft = '0px'
    mcTabPane.style.paddingRight = '35px'
    urmpTabContent.appendChild(mcTabPane)
    const mcMenu = WMEURMPT.createElement('center')
    mcTabPane.appendChild(mcMenu)
    elt = WMEURMPT.createElement('a', 'mct-a-markallvisited')
    elt.innerHTML = WMEURMPT.convertHtml('Mark all as visited')
    elt.href = '#'
    elt.onclick = WMEURMPT.markAllMCAsVisited
    mcMenu.appendChild(elt)
    elt = WMEURMPT.createElement('span')
    elt.innerHTML = WMEURMPT.convertHtml('|')
    mcMenu.appendChild(elt)
    elt = WMEURMPT.createElement('a', 'mct-a-clearAll')
    elt.innerHTML = WMEURMPT.convertHtml('Clear all')
    elt.href = '#'
    elt.onclick = WMEURMPT.clearAllMC
    mcMenu.appendChild(elt)
    elt = WMEURMPT.createElement('span')
    elt.innerHTML = WMEURMPT.convertHtml('|')
    mcMenu.appendChild(elt)
    elt = WMEURMPT.createElement('div')
    content = '<ul class="urt-filter-list">'
    content += '<li title="Show MCs in my drive areas"><input type="checkbox" id="mct-checkbox-filterHideOutOfMyDriveArea"> Hide out of my drive area</li>'
    if (WMEURMPT.uam) {
      content += '<li title="Show MCs in my managed areas"><input type="checkbox" id="mct-checkbox-filterHideOutOfMyManagedArea"> Hide out of my managed area</li>'
    }
    content += '<li title="Show MCs I have never seen"><input type="checkbox" id="mct-checkbox-filterHideVisited"> Hide visited</li>'
    content += '<li title="Show white listed MCs"><input type="checkbox" id="mct-checkbox-filterHideBlacklisted"> Hide black listed</li>'
    content += '<li title="Show black listed MCs"><input type="checkbox" id="mct-checkbox-filterHideWhitelisted"> Hide white listed</li>'
    content += '<li title="Show only nth first MCs"><input type="checkbox" id="mct-checkbox-filterHideLimitTo"> Limit to: <input type="text" id="mct-filterLimitTo" value="' + WMEURMPT.currentMCLimitTo + '"></input></li>'
    content += '<li title="Show MC if subject or body contains keyword"><input type="checkbox" id="mct-checkbox-filterHideNotKW"> Subject/Body keyword: <input type="text" id="mct-filterKW" value="' + WMEURMPT.currentMCKeyWord + '"></input></li>'
    content += '<li title="Show only inside area"><input type="checkbox" id="mct-checkbox-filterHideOnlyArea"> Hide all but: <select style="height: 25px" id="mct-filterOnlyArea">'
    content += '</select></li>'
    content += '</ul>'
    mcTabPane.appendChild(elt)
    panel = new WMEURMPT.PopupPannel('FilterMC', '100%', '100%', '#93c4d3')
    panel.setTriggerInnerHTML('Filters')
    panel.setContentsInnerHTML(content)
    panel.installInside(elt)
    elt = WMEURMPT.createElement('div', 'mct-list')
    mcTabPane.appendChild(elt)
    const purTabPane = WMEURMPT.createElement('section', 'urmp-tabs-pur')
    purTabPane.className = 'tab-pane'
    purTabPane.style.paddingLeft = '0px'
    purTabPane.style.paddingRight = '35px'
    urmpTabContent.appendChild(purTabPane)
    const purMenu = WMEURMPT.createElement('center')
    purTabPane.appendChild(purMenu)
    elt = WMEURMPT.createElement('a', 'purt-a-markallvisited')
    elt.innerHTML = WMEURMPT.convertHtml('Mark all as visited')
    elt.href = '#'
    elt.onclick = WMEURMPT.markAllPURAsVisited
    purMenu.appendChild(elt)
    elt = WMEURMPT.createElement('span')
    elt.innerHTML = WMEURMPT.convertHtml('|')
    purMenu.appendChild(elt)
    elt = WMEURMPT.createElement('a', 'purt-a-clearAll')
    elt.innerHTML = WMEURMPT.convertHtml('Clear all')
    elt.href = '#'
    elt.onclick = WMEURMPT.clearAllPUR
    purMenu.appendChild(elt)
    elt = WMEURMPT.createElement('span')
    elt.innerHTML = WMEURMPT.convertHtml('|')
    purMenu.appendChild(elt)
    elt = WMEURMPT.createElement('div')
    content = '<ul class="urt-filter-list">'
    content += '<li><input type="checkbox" id="pur-checkbox-filterInvert"><b>Invert filters</b></li>'
    content += '<li title="Show PURs in my drive areas"><input type="checkbox" id="purt-checkbox-filterHideOutOfMyDriveArea"> Hide out of my drive area</li>'
    if (WMEURMPT.uam) {
      content += '<li title="Show PURs in my managed areas"><input type="checkbox" id="purt-checkbox-filterHideOutOfMyManagedArea"> Hide out of my managed area</li>'
    }
    content += '<li title="Show PURs I have never seen"><input type="checkbox" id="purt-checkbox-filterHideVisited"> Hide visited</li>'
    content += '<li title="Show white listed PURs"><input type="checkbox" id="purt-checkbox-filterHideBlacklisted"> Hide black listed</li>'
    content += '<li title="Show black listed PURs"><input type="checkbox" id="purt-checkbox-filterHideWhitelisted"> Hide white listed</li>'
    content += '<li title="Show only nth first PURs"><input type="checkbox" id="purt-checkbox-filterHideLimitTo"> Limit to: <input type="text" id="purt-filterLimitTo" value="' + WMEURMPT.currentPURLimitTo + '"></input></li>'
    content += '<li title="Show PUR if subject or body contains keyword"><input type="checkbox" id="purt-checkbox-filterHideNotKW"> Subject/Body keyword: <input type="text" id="purt-filterKW" value="' + WMEURMPT.currentPURKeyWord + '"></input></li>'
    content += '<li title="Show only one categorie"><input type="checkbox" id="purt-checkbox-filterHideOnlyCategorie"> Hide all but: <select style="height: 25px" id="purt-filterOnlyCategorie">'
    const PURCategories = WMEURMPT.objectToList(WMEURMPT.getFullPURCategoriesFromCategories())
    for (let i = 0; i < PURCategories.length; i++) {
      content += '<option value="' + PURCategories[i] + '"' + (WMEURMPT.currentPUROnlyCategorie === PURCategories[i] ? ' selected' : '') + '>' + PURCategories[i] + '</option>'
    }
    content += '</select></li>'
    content += '<li title="Show only inside area"><input type="checkbox" id="purt-checkbox-filterHideOnlyArea"> Hide all but: <select style="height: 25px" id="purt-filterOnlyArea">'
    content += '</select></li>'
    content += '</ul>'
    purTabPane.appendChild(elt)
    panel = new WMEURMPT.PopupPannel('FilterPUR', '100%', '100%', '#93c4d3')
    panel.setTriggerInnerHTML('Filters')
    panel.setContentsInnerHTML(content)
    panel.installInside(elt)
    elt = WMEURMPT.createElement('div', 'purt-list')
    purTabPane.appendChild(elt)
    const osTabPane = WMEURMPT.createElement('section', 'urmp-tabs-os')
    osTabPane.className = 'tab-pane'
    osTabPane.style.paddingLeft = '0px'
    osTabPane.style.paddingRight = '40px'
    urmpTabContent.appendChild(osTabPane)
    const divStats = WMEURMPT.createElement('div', 'urmpt-stats')
    osTabPane.appendChild(divStats)
    const areasTabPane = WMEURMPT.createElement('section', 'urmp-tabs-areas')
    areasTabPane.className = 'tab-pane'
    areasTabPane.style.paddingLeft = '0px'
    areasTabPane.style.paddingRight = '40px'
    urmpTabContent.appendChild(areasTabPane)
    if (WMEURMPT.ul >= 8 || WMEURMPT.me.isCountryManager()) {
      const divCM = WMEURMPT.createElement('div')
      divCM.innerHTML = WMEURMPT.convertHtml('Add country(ies) or subset(s) to scan list.<br/>')
      const divInput = WMEURMPT.createElement('div')
      divInput.style.whiteSpace = 'nowrap'
      const countryList = WMEURMPT.createElement('select', 'urmpt-countryList')
      countryList.style.width = 'calc(100% - 45px)'
      divInput.appendChild(countryList)
      window.setTimeout(WMEURMPT.initCountryList)
      const addButton = WMEURMPT.createElement('button')
      addButton.innerHTML = WMEURMPT.convertHtml('Add')
      addButton.onclick = WMEURMPT.addCountryToAreaList
      divInput.appendChild(addButton)
      divCM.appendChild(divInput)
      divCM.insertAdjacentHTML('beforeend', '<br/>Your country scan list:<br/>')
      const divCountryScanList = WMEURMPT.createElement('div', 'urmpt-countryscanlist')
      divCM.appendChild(divCountryScanList)
      areasTabPane.appendChild(divCM)
      areasTabPane.appendChild(WMEURMPT.createElement('hr'))
    }
    const divCA = WMEURMPT.createElement('div')
    const divAddCA = WMEURMPT.createElement('div')
    divAddCA.style.display = 'none'
    divAddCA.style.paddingLeft = '10px'
    const elAddCAmenu = WMEURMPT.createElement('a')
    elAddCAmenu.innerHTML = WMEURMPT.convertHtml('\u25b6 Add custom area')
    elAddCAmenu.href = '#'
    elAddCAmenu.onclick = function () {
      if (divAddCA.style.display === 'none') {
        divAddCA.style.display = 'block'
        this.innerHTML = WMEURMPT.convertHtml('\u25bc Add custom area')
      } else {
        divAddCA.style.display = 'none'
        this.innerHTML = WMEURMPT.convertHtml('\u25b6 Add custom area')
      }
    }
    const inputFromPOI = WMEURMPT.createElement('div')
    inputFromPOI.innerHTML = WMEURMPT.convertHtml('FROM AN UNSAVED POI AREA')
    const inputFromPOIName = WMEURMPT.createElement('div')
    inputFromPOIName.innerHTML = WMEURMPT.convertHtml('Give a name to your area:<input type="text" id="urmpt-areas-frompoi-name" />')
    const inputFromPOIButton = WMEURMPT.createElement('div')
    inputFromPOIButton.innerHTML = WMEURMPT.convertHtml('Then, <a href="#" id="urmpt-areas-frompoi-add"/>add</a>')
    inputFromPOI.appendChild(inputFromPOIName)
    inputFromPOI.appendChild(inputFromPOIButton)
    divAddCA.appendChild(inputFromPOI)
    divAddCA.appendChild(WMEURMPT.createElement('hr'))
    const inputFromLL = WMEURMPT.createElement('div')
    inputFromLL.innerHTML = WMEURMPT.convertHtml('FROM LON/LAT BOUNDING BOX')
    const input1 = WMEURMPT.createElement('div')
    input1.innerHTML = WMEURMPT.convertHtml('Fill lon/lat top left corner<br/>or <a href="#" id="urmpt-areas-fill-tl">get it from your top left screen</a><br/>lon:<input type="text" size="10" maxlentgh="10" id="urmpt-areas-tl-lon" />lat:<input type="text" size="10" maxlentgh="10" id="urmpt-areas-tl-lat" />')
    const input2 = WMEURMPT.createElement('div')
    input2.innerHTML = WMEURMPT.convertHtml('Fill lon/lat bottom right corner<br/>or <a href="#" id="urmpt-areas-fill-br">get it from your bottom right screen</a><br/>lon:<input type="text" size="10" maxlentgh="10" id="urmpt-areas-br-lon" />lat:<input type="text" size="10" maxlentgh="10" id="urmpt-areas-br-lat" />')
    const input3 = WMEURMPT.createElement('div')
    input3.innerHTML = WMEURMPT.convertHtml('Give a name to your area:<input type="text" id="urmpt-areas-name" />')
    const input4 = WMEURMPT.createElement('div')
    input4.innerHTML = WMEURMPT.convertHtml('Then, <a href="#" id="urmpt-areas-name-add"/>add</a>')
    inputFromLL.appendChild(input1)
    inputFromLL.appendChild(input2)
    inputFromLL.appendChild(input3)
    inputFromLL.appendChild(input4)
    divAddCA.appendChild(inputFromLL)
    divAddCA.appendChild(WMEURMPT.createElement('hr'))
    const inputFromWKT = WMEURMPT.createElement('div')
    inputFromWKT.innerHTML = WMEURMPT.convertHtml('FROM WKT')
    const inputFromWKTFile = WMEURMPT.createElement('div')
    inputFromWKTFile.innerHTML = WMEURMPT.convertHtml('<input type="file" id="urmpt-areas-wktfile" name="files[]" />')
    const inputFromWKTName = WMEURMPT.createElement('div')
    inputFromWKTName.innerHTML = WMEURMPT.convertHtml('Give a name to your area:<input type="text" id="urmpt-areas-wktfile-name" />')
    const inputFromWKTAdd = WMEURMPT.createElement('div')
    inputFromWKTAdd.innerHTML = WMEURMPT.convertHtml('Then, <a href="#" id="urmpt-areas-wktfile-add"/>add</a>')
    inputFromWKT.appendChild(inputFromWKTName)
    inputFromWKT.appendChild(inputFromWKTFile)
    inputFromWKT.appendChild(inputFromWKTAdd)
    divAddCA.appendChild(inputFromWKT)
    divAddCA.appendChild(WMEURMPT.createElement('hr'))
    const inputFromJSON = WMEURMPT.createElement('div')
    inputFromJSON.innerHTML = WMEURMPT.convertHtml('FROM JSON')
    const inputFromJSONFile = WMEURMPT.createElement('div')
    inputFromJSONFile.innerHTML = WMEURMPT.convertHtml('<input type="file" id="urmpt-areas-jsonfile" name="files[]" />')
    const inputFromJSONAdd = WMEURMPT.createElement('div')
    inputFromJSONAdd.innerHTML = WMEURMPT.convertHtml('Then, <a href="#" id="urmpt-areas-jsonfile-add"/>add</a>')
    inputFromJSON.appendChild(inputFromJSONFile)
    inputFromJSON.appendChild(inputFromJSONAdd)
    divAddCA.appendChild(inputFromJSON)
    divCA.appendChild(elAddCAmenu)
    divCA.appendChild(divAddCA)
    divCA.insertAdjacentHTML('beforeend', '<br/>Your custom area scan list:<br/>')
    const divCustomAreaScanList = WMEURMPT.createElement('div', 'urmpt-custom-scan-list')
    divCA.appendChild(divCustomAreaScanList)
    areasTabPane.appendChild(divCA)
    const settingsTabPane = WMEURMPT.createElement('section', 'urmp-tabs-settings')
    settingsTabPane.className = 'tab-pane'
    settingsTabPane.style.paddingRight = '35px'
    urmpTabContent.appendChild(settingsTabPane)
    const urDescriptionColumnWidth = WMEURMPT.createElement('span')
    urDescriptionColumnWidth.innerHTML = WMEURMPT.convertHtml('UR description column width: <input style="height:20px" type="text" size="3" id="urmpt-setting-urdescriptionwidth" value="' + WMEURMPT.URDescriptionMaxLength + '"/><br>')
    settingsTabPane.appendChild(urDescriptionColumnWidth)
    const mpDescriptionColumnWidth = WMEURMPT.createElement('span')
    mpDescriptionColumnWidth.innerHTML = WMEURMPT.convertHtml('MP description column width: <input style="height:20px" type="text" size="3" id="urmpt-setting-mpdescriptionwidth" value="' + WMEURMPT.MPDescriptionMaxLength + '"/><br>')
    settingsTabPane.appendChild(mpDescriptionColumnWidth)
    const mcSubjectColumnWidth = WMEURMPT.createElement('span')
    mcSubjectColumnWidth.innerHTML = WMEURMPT.convertHtml('MC subject column width: <input style="height:20px" type="text" size="3" id="urmpt-setting-mcsubjectwidth" value="' + WMEURMPT.MCSubjectMaxLength + '"/><br>')
    settingsTabPane.appendChild(mcSubjectColumnWidth)
    const mcBodyColumnWidth = WMEURMPT.createElement('span')
    mcBodyColumnWidth.innerHTML = WMEURMPT.convertHtml('MC body column width: <input style="height:20px" type="text" size="3" id="urmpt-setting-mcbodywidth" value="' + WMEURMPT.MCBodyMaxLength + '"/><br>')
    settingsTabPane.appendChild(mcBodyColumnWidth)
    const purCategoriesColumnWidth = WMEURMPT.createElement('span')
    purCategoriesColumnWidth.innerHTML = WMEURMPT.convertHtml('PUR categories column width: <input style="height:20px" type="text" size="3" id="urmpt-setting-purcategorieswidth" value="' + WMEURMPT.PURCategoriesMaxLength + '"/><br>')
    settingsTabPane.appendChild(purCategoriesColumnWidth)
    const purNameColumnWidth = WMEURMPT.createElement('span')
    purNameColumnWidth.innerHTML = WMEURMPT.convertHtml('PUR name column width: <input style="height:20px" type="text" size="3" id="urmpt-setting-purnamewidth" value="' + WMEURMPT.PURNameMaxLength + '"/><br>')
    settingsTabPane.appendChild(purNameColumnWidth)
    const urTaggedListSpan = WMEURMPT.createElement('span')
    urTaggedListSpan.innerHTML = WMEURMPT.convertHtml('UR Tag keywords: <input style="height:20px;width:100%;" type="text" id="urmpt-setting-urtaglist" value="' + WMEURMPT.taggedURList.join(';') + '"/>')
    settingsTabPane.appendChild(urTaggedListSpan)
    const urAgeColumnSpan = WMEURMPT.createElement('span')
    urAgeColumnSpan.innerHTML = WMEURMPT.convertHtml('<input type="checkbox" id="urmpt-setting-uragecolislastcomment" ' + (WMEURMPT.URAgeColIsLastComment ? 'checked ' : '') + '/> UR age column is last comment age<br>')
    settingsTabPane.appendChild(urAgeColumnSpan)
    const disableScrollingSpan = WMEURMPT.createElement('span')
    disableScrollingSpan.innerHTML = WMEURMPT.convertHtml('<input type="checkbox" id="urmpt-setting-disablescrolling" ' + (WMEURMPT.disableScrolling ? 'checked ' : '') + '/> Disable text scrolling in tables')
    settingsTabPane.appendChild(disableScrollingSpan)
    window.setTimeout(WMEURMPT.setupCAEvents)
    window.setTimeout(WMEURMPT.updateScanGroup)
    const userTabs = WMEURMPT.getId('user-tabs')
    const sidePanel = WMEURMPT.getId('sidepanel-issue-tracker')
    const navTabs = WMEURMPT.getElementsByClassName('nav-tabs', userTabs)[0]
    const tabContent = sidePanel.parentNode
    const newtab = WMEURMPT.createElement('li')
    newtab.innerHTML = WMEURMPT.convertHtml('<a title="UR-MP Tracking" href="#sidepanel-urt" data-toggle="tab"><span class="fa fa-map-marker icon-map-marker" style="color: red;"></span></a>')
    navTabs.appendChild(newtab)
    addon.id = 'sidepanel-urt'
    addon.className = 'tab-pane'
    addon.style.marginLeft = '-10px'
    tabContent.appendChild(addon)
    if (WMEURMPT.currentURFilter & WMEURMPT.URFilterList.hideClosed && WMEURMPT.ul >= WMEURMPT.rl4cp) {
      WMEURMPT.getId('urt-checkbox-filterHideClosed').checked = true
    }
    if (WMEURMPT.currentURFilter & WMEURMPT.URFilterList.hideWithoutCommentFromMe) {
      WMEURMPT.getId('urt-checkbox-filterHideWithoutCommentFromMe').checked = true
    }
    if (WMEURMPT.currentURFilter & WMEURMPT.URFilterList.hideWithCommentCount) {
      WMEURMPT.getId('urt-checkbox-filterHideWithCommentCount').checked = true
    }
    if (WMEURMPT.currentURFilter & WMEURMPT.URFilterList.hideNoNewComment) {
      WMEURMPT.getId('urt-checkbox-filterHideNoNewComment').checked = true
    }
    if (WMEURMPT.currentURFilter & WMEURMPT.URFilterList.hideOutOfMyDriveArea) {
      WMEURMPT.getId('urt-checkbox-filterHideOutOfMyDriveArea').checked = true
    }
    if (WMEURMPT.currentURFilter & WMEURMPT.URFilterList.hideOutOfMyManagedArea && WMEURMPT.uam) {
      WMEURMPT.getId('urt-checkbox-filterHideOutOfMyManagedArea').checked = true
    }
    if (WMEURMPT.currentURFilter & WMEURMPT.URFilterList.hideVisited) {
      WMEURMPT.getId('urt-checkbox-filterHideVisited').checked = true
    }
    if (WMEURMPT.currentURFilter & WMEURMPT.URFilterList.hideBlacklisted) {
      WMEURMPT.getId('urt-checkbox-filterHideBlacklisted').checked = true
    }
    if (WMEURMPT.currentURFilter & WMEURMPT.URFilterList.hideWhitelisted) {
      WMEURMPT.getId('urt-checkbox-filterHideWhitelisted').checked = true
    }
    if (WMEURMPT.currentURFilter & WMEURMPT.URFilterList.hideGE) {
      WMEURMPT.getId('urt-checkbox-filterHideGE').checked = true
    }
    if (WMEURMPT.currentURFilter & WMEURMPT.URFilterList.hideNotKW) {
      WMEURMPT.getId('urt-checkbox-filterHideNotKW').checked = true
    }
    if (WMEURMPT.currentURFilter & WMEURMPT.URFilterList.hideLimitTo) {
      WMEURMPT.getId('urt-checkbox-filterHideLimitTo').checked = true
    }
    if (WMEURMPT.currentURFilter & WMEURMPT.URFilterList.hideType) {
      WMEURMPT.getId('urt-checkbox-filterHideOnlyType').checked = true
    }
    if (WMEURMPT.currentURFilter & WMEURMPT.URFilterList.hideArea) {
      WMEURMPT.getId('urt-checkbox-filterHideOnlyArea').checked = true
    }
    if (WMEURMPT.currentURFilter & WMEURMPT.URFilterList.hideLastCommentFromEditor) {
      WMEURMPT.getId('urt-checkbox-filterHideLastCommentFromEditor').checked = true
    }
    if (WMEURMPT.currentURFilter & WMEURMPT.URFilterList.hideTagged) {
      WMEURMPT.getId('urt-checkbox-filterHideTagged').checked = true
    }
    WMEURMPT.getId('urt-checkbox-filterInvert').onclick = WMEURMPT.toggleURInvertFilter
    WMEURMPT.getId('urt-checkbox-filterInvert').checked = WMEURMPT.urtInvertFilter
    if (WMEURMPT.ul >= WMEURMPT.rl4cp) {
      WMEURMPT.getId('urt-checkbox-filterHideClosed').onclick = WMEURMPT.toggleURFilterHideClosed
    }
    WMEURMPT.getId('urt-checkbox-filterHideWithoutCommentFromMe').onclick = WMEURMPT.toggleURFilterHideWithoutCommentFromMe
    WMEURMPT.getId('urt-checkbox-filterHideWithCommentCount').onclick = WMEURMPT.toggleURFilterHideWithCommentCount
    WMEURMPT.getId('urt-checkbox-filterHideNoNewComment').onclick = WMEURMPT.toggleURFilterHideNoNewComment
    WMEURMPT.getId('urt-checkbox-filterHideOutOfMyDriveArea').onclick = WMEURMPT.toggleURFilterHideOutOfMyDriveArea
    if (WMEURMPT.uam) {
      WMEURMPT.getId('urt-checkbox-filterHideOutOfMyManagedArea').onclick = WMEURMPT.toggleURFilterHideOutOfMyManagedArea
    }
    WMEURMPT.getId('urt-checkbox-filterHideVisited').onclick = WMEURMPT.toggleURFilterHideVisited
    WMEURMPT.getId('urt-checkbox-filterHideBlacklisted').onclick = WMEURMPT.toggleURFilterHideBlacklisted
    WMEURMPT.getId('urt-checkbox-filterHideWhitelisted').onclick = WMEURMPT.toggleURFilterHideWhitelisted
    WMEURMPT.getId('urt-checkbox-filterHideGE').onclick = WMEURMPT.toggleURFilterHideGE
    WMEURMPT.getId('urt-checkbox-filterHideNotKW').onclick = WMEURMPT.toggleURFilterHideNotKW
    WMEURMPT.getId('urt-checkbox-filterHideLimitTo').onclick = WMEURMPT.toggleURFilterHideLimitTo
    WMEURMPT.getId('urt-checkbox-filterHideOnlyType').onclick = WMEURMPT.toggleURFilterHideOnlyType
    WMEURMPT.getId('urt-checkbox-filterHideOnlyArea').onclick = WMEURMPT.toggleURFilterHideOnlyArea
    WMEURMPT.getId('urt-filterHideWithCommentCount').onkeypress = WMEURMPT.URCommentsCountChanged
    WMEURMPT.getId('urt-filterHideWithCommentCount').onpaste = WMEURMPT.URCommentsCountChanged
    WMEURMPT.getId('urt-filterHideWithCommentCount').oninput = WMEURMPT.URCommentsCountChanged
    WMEURMPT.getId('urt-filterKW').onkeypress = WMEURMPT.URKeywordChanged
    WMEURMPT.getId('urt-filterKW').onpaste = WMEURMPT.URKeywordChanged
    WMEURMPT.getId('urt-filterKW').oninput = WMEURMPT.URKeywordChanged
    WMEURMPT.getId('urt-filterLimitTo').onkeypress = WMEURMPT.URLimitToChanged
    WMEURMPT.getId('urt-filterLimitTo').onpaste = WMEURMPT.URLimitToChanged
    WMEURMPT.getId('urt-filterLimitTo').oninput = WMEURMPT.URLimitToChanged
    WMEURMPT.getId('urt-filterOnlyType').onchange = WMEURMPT.UROnlyTypeChanged
    WMEURMPT.getId('urt-filterOnlyArea').onchange = WMEURMPT.UROnlyAreaChanged
    WMEURMPT.getId('urt-checkbox-filterHideLastCommentFromEditor').onclick = WMEURMPT.toggleURFilterHideLastCommentFromEditor
    WMEURMPT.getId('urt-checkbox-filterHideTagged').onclick = WMEURMPT.toggleURFilterHideTagged
    if (WMEURMPT.currentMPFilter & WMEURMPT.MPFilterList.hideClosed && WMEURMPT.ul >= WMEURMPT.rl4cp) {
      WMEURMPT.getId('mpt-checkbox-filterHideClosed').checked = true
    }
    if (WMEURMPT.currentMPFilter & WMEURMPT.MPFilterList.hideOutOfMyDriveArea) {
      WMEURMPT.getId('mpt-checkbox-filterHideOutOfMyDriveArea').checked = true
    }
    if (WMEURMPT.currentMPFilter & WMEURMPT.MPFilterList.hideOutOfMyManagedArea && WMEURMPT.uam) {
      WMEURMPT.getId('mpt-checkbox-filterHideOutOfMyManagedArea').checked = true
    }
    if (WMEURMPT.currentMPFilter & WMEURMPT.MPFilterList.hideVisited) {
      WMEURMPT.getId('mpt-checkbox-filterHideVisited').checked = true
    }
    if (WMEURMPT.currentMPFilter & WMEURMPT.MPFilterList.hideBlacklisted) {
      WMEURMPT.getId('mpt-checkbox-filterHideBlacklisted').checked = true
    }
    if (WMEURMPT.currentMPFilter & WMEURMPT.MPFilterList.hideWhitelisted) {
      WMEURMPT.getId('mpt-checkbox-filterHideWhitelisted').checked = true
    }
    if (WMEURMPT.currentMPFilter & WMEURMPT.MPFilterList.hideLimitTo) {
      WMEURMPT.getId('mpt-checkbox-filterHideLimitTo').checked = true
    }
    if (WMEURMPT.currentMPFilter & WMEURMPT.MPFilterList.hideType) {
      WMEURMPT.getId('mpt-checkbox-filterHideOnlyType').checked = true
    }
    if (WMEURMPT.currentMPFilter & WMEURMPT.MPFilterList.hideArea) {
      WMEURMPT.getId('mpt-checkbox-filterHideOnlyArea').checked = true
    }
    if (WMEURMPT.ul >= WMEURMPT.rl4cp) {
      WMEURMPT.getId('mpt-checkbox-filterHideClosed').onclick = WMEURMPT.toggleMPFilterHideClosed
    }
    WMEURMPT.getId('mpt-checkbox-filterHideOutOfMyDriveArea').onclick = WMEURMPT.toggleMPFilterHideOutOfMyDriveArea
    if (WMEURMPT.uam) {
      WMEURMPT.getId('mpt-checkbox-filterHideOutOfMyManagedArea').onclick = WMEURMPT.toggleMPFilterHideOutOfMyManagedArea
    }
    WMEURMPT.getId('mpt-checkbox-filterHideVisited').onclick = WMEURMPT.toggleMPFilterHideVisited
    WMEURMPT.getId('mpt-checkbox-filterHideBlacklisted').onclick = WMEURMPT.toggleMPFilterHideBlacklisted
    WMEURMPT.getId('mpt-checkbox-filterHideWhitelisted').onclick = WMEURMPT.toggleMPFilterHideWhitelisted
    WMEURMPT.getId('mpt-checkbox-filterHideLimitTo').onclick = WMEURMPT.toggleMPFilterHideLimitTo
    WMEURMPT.getId('mpt-checkbox-filterHideOnlyType').onclick = WMEURMPT.toggleMPFilterHideOnlyType
    WMEURMPT.getId('mpt-checkbox-filterHideOnlyArea').onclick = WMEURMPT.toggleMPFilterHideOnlyArea
    WMEURMPT.getId('mpt-filterLimitTo').onkeypress = WMEURMPT.MPLimitToChanged
    WMEURMPT.getId('mpt-filterLimitTo').onpaste = WMEURMPT.MPLimitToChanged
    WMEURMPT.getId('mpt-filterLimitTo').oninput = WMEURMPT.MPLimitToChanged
    WMEURMPT.getId('mpt-filterOnlyType').onchange = WMEURMPT.MPOnlyTypeChanged
    WMEURMPT.getId('mpt-filterOnlyArea').onchange = WMEURMPT.MPOnlyAreaChanged
    if (WMEURMPT.currentMCFilter & WMEURMPT.MCFilterList.hideOutOfMyDriveArea) {
      WMEURMPT.getId('mct-checkbox-filterHideOutOfMyDriveArea').checked = true
    }
    if (WMEURMPT.currentMCFilter & WMEURMPT.MCFilterList.hideOutOfMyManagedArea && WMEURMPT.uam) {
      WMEURMPT.getId('mct-checkbox-filterHideOutOfMyManagedArea').checked = true
    }
    if (WMEURMPT.currentMCFilter & WMEURMPT.MCFilterList.hideVisited) {
      WMEURMPT.getId('mct-checkbox-filterHideVisited').checked = true
    }
    if (WMEURMPT.currentMCFilter & WMEURMPT.MCFilterList.hideBlacklisted) {
      WMEURMPT.getId('mct-checkbox-filterHideBlacklisted').checked = true
    }
    if (WMEURMPT.currentMCFilter & WMEURMPT.MCFilterList.hideWhitelisted) {
      WMEURMPT.getId('mct-checkbox-filterHideWhitelisted').checked = true
    }
    if (WMEURMPT.currentMCFilter & WMEURMPT.MCFilterList.hideNotKW) {
      WMEURMPT.getId('mct-checkbox-filterHideNotKW').checked = true
    }
    if (WMEURMPT.currentMCFilter & WMEURMPT.MCFilterList.hideLimitTo) {
      WMEURMPT.getId('mct-checkbox-filterHideLimitTo').checked = true
    }
    if (WMEURMPT.currentMCFilter & WMEURMPT.MCFilterList.hideArea) {
      WMEURMPT.getId('mct-checkbox-filterHideOnlyArea').checked = true
    }
    WMEURMPT.getId('mct-checkbox-filterHideOutOfMyDriveArea').onclick = WMEURMPT.toggleMCFilterHideOutOfMyDriveArea
    if (WMEURMPT.uam) {
      WMEURMPT.getId('mct-checkbox-filterHideOutOfMyManagedArea').onclick = WMEURMPT.toggleMCFilterHideOutOfMyManagedArea
    }
    WMEURMPT.getId('mct-checkbox-filterHideVisited').onclick = WMEURMPT.toggleMCFilterHideVisited
    WMEURMPT.getId('mct-checkbox-filterHideBlacklisted').onclick = WMEURMPT.toggleMCFilterHideBlacklisted
    WMEURMPT.getId('mct-checkbox-filterHideWhitelisted').onclick = WMEURMPT.toggleMCFilterHideWhitelisted
    WMEURMPT.getId('mct-checkbox-filterHideLimitTo').onclick = WMEURMPT.toggleMCFilterHideLimitTo
    WMEURMPT.getId('mct-checkbox-filterHideNotKW').onclick = WMEURMPT.toggleMCFilterHideNotKW
    WMEURMPT.getId('mct-checkbox-filterHideOnlyArea').onclick = WMEURMPT.toggleMCFilterHideOnlyArea
    WMEURMPT.getId('mct-filterKW').onkeypress = WMEURMPT.MCKeywordChanged
    WMEURMPT.getId('mct-filterKW').onpaste = WMEURMPT.MCKeywordChanged
    WMEURMPT.getId('mct-filterKW').oninput = WMEURMPT.MCKeywordChanged
    WMEURMPT.getId('mct-filterLimitTo').onkeypress = WMEURMPT.MCLimitToChanged
    WMEURMPT.getId('mct-filterLimitTo').onpaste = WMEURMPT.MCLimitToChanged
    WMEURMPT.getId('mct-filterLimitTo').oninput = WMEURMPT.MCLimitToChanged
    WMEURMPT.getId('mct-filterOnlyArea').onchange = WMEURMPT.MCOnlyAreaChanged
    if (WMEURMPT.currentPURFilter & WMEURMPT.PURFilterList.hideOutOfMyDriveArea) {
      WMEURMPT.getId('purt-checkbox-filterHideOutOfMyDriveArea').checked = true
    }
    if (WMEURMPT.currentPURFilter & WMEURMPT.PURFilterList.hideOutOfMyManagedArea && WMEURMPT.uam) {
      WMEURMPT.getId('purt-checkbox-filterHideOutOfMyManagedArea').checked = true
    }
    if (WMEURMPT.currentPURFilter & WMEURMPT.PURFilterList.hideVisited) {
      WMEURMPT.getId('purt-checkbox-filterHideVisited').checked = true
    }
    if (WMEURMPT.currentPURFilter & WMEURMPT.PURFilterList.hideBlacklisted) {
      WMEURMPT.getId('purt-checkbox-filterHideBlacklisted').checked = true
    }
    if (WMEURMPT.currentPURFilter & WMEURMPT.PURFilterList.hideWhitelisted) {
      WMEURMPT.getId('purt-checkbox-filterHideWhitelisted').checked = true
    }
    if (WMEURMPT.currentPURFilter & WMEURMPT.PURFilterList.hideCategorie) {
      WMEURMPT.getId('purt-checkbox-filterHideOnlyCategorie').checked = true
    }
    if (WMEURMPT.currentPURFilter & WMEURMPT.PURFilterList.hideNotKW) {
      WMEURMPT.getId('purt-checkbox-filterHideNotKW').checked = true
    }
    if (WMEURMPT.currentPURFilter & WMEURMPT.PURFilterList.hideLimitTo) {
      WMEURMPT.getId('purt-checkbox-filterHideLimitTo').checked = true
    }
    if (WMEURMPT.currentPURFilter & WMEURMPT.PURFilterList.hideArea) {
      WMEURMPT.getId('purt-checkbox-filterHideOnlyArea').checked = true
    }
    WMEURMPT.getId('purt-checkbox-filterHideOutOfMyDriveArea').onclick = WMEURMPT.togglePURFilterHideOutOfMyDriveArea
    if (WMEURMPT.uam) {
      WMEURMPT.getId('purt-checkbox-filterHideOutOfMyManagedArea').onclick = WMEURMPT.togglePURFilterHideOutOfMyManagedArea
    }
    WMEURMPT.getId('pur-checkbox-filterInvert').onchange = WMEURMPT.togglePURInvertFilter
    WMEURMPT.getId('pur-checkbox-filterInvert').checked = WMEURMPT.purInvertFilter
    WMEURMPT.getId('purt-checkbox-filterHideVisited').onclick = WMEURMPT.togglePURFilterHideVisited
    WMEURMPT.getId('purt-checkbox-filterHideBlacklisted').onclick = WMEURMPT.togglePURFilterHideBlacklisted
    WMEURMPT.getId('purt-checkbox-filterHideWhitelisted').onclick = WMEURMPT.togglePURFilterHideWhitelisted
    WMEURMPT.getId('purt-checkbox-filterHideOnlyCategorie').onclick = WMEURMPT.togglePURFilterHideOnlyCategorie
    WMEURMPT.getId('purt-checkbox-filterHideLimitTo').onclick = WMEURMPT.togglePURFilterHideLimitTo
    WMEURMPT.getId('purt-checkbox-filterHideNotKW').onclick = WMEURMPT.togglePURFilterHideNotKW
    WMEURMPT.getId('purt-checkbox-filterHideOnlyArea').onclick = WMEURMPT.togglePURFilterHideOnlyArea
    WMEURMPT.getId('purt-filterKW').onkeypress = WMEURMPT.PURKeywordChanged
    WMEURMPT.getId('purt-filterKW').onpaste = WMEURMPT.PURKeywordChanged
    WMEURMPT.getId('purt-filterKW').oninput = WMEURMPT.PURKeywordChanged
    WMEURMPT.getId('purt-filterLimitTo').onkeypress = WMEURMPT.PURLimitToChanged
    WMEURMPT.getId('purt-filterLimitTo').onpaste = WMEURMPT.PURLimitToChanged
    WMEURMPT.getId('purt-filterLimitTo').oninput = WMEURMPT.PURLimitToChanged
    WMEURMPT.getId('purt-filterOnlyCategorie').onchange = WMEURMPT.PUROnlyCategorieChanged
    WMEURMPT.getId('purt-filterOnlyArea').onchange = WMEURMPT.PUROnlyAreaChanged
    if (WMEURMPT.displayLegend) {
      WMEURMPT.getId('urt-close-legend').onclick = WMEURMPT.closeLegend
    }
    WMEURMPT.getId('urmpt-onoff').onclick = WMEURMPT.enableOrDisable
    WMEURMPT.getId('urmpt-donoff').onclick = WMEURMPT.enableOrDisableDistance
    WMEURMPT.getId('urmpt-asonoff').onclick = WMEURMPT.enableOrDisableAutoScan
    WMEURMPT.getId('urmpt-suronoff').onclick = WMEURMPT.enableOrDisableScanUR
    WMEURMPT.getId('urmpt-smponoff').onclick = WMEURMPT.enableOrDisableScanMP
    WMEURMPT.getId('urmpt-smconoff').onclick = WMEURMPT.enableOrDisableScanMC
    WMEURMPT.getId('urmpt-spuronoff').onclick = WMEURMPT.enableOrDisableScanPUR
    WMEURMPT.getId('urmpt-setting-urdescriptionwidth').onkeypress = WMEURMPT.settingsSetURDescriptionWidth
    WMEURMPT.getId('urmpt-setting-urdescriptionwidth').onpaste = WMEURMPT.settingsSetURDescriptionWidth
    WMEURMPT.getId('urmpt-setting-urdescriptionwidth').oninput = WMEURMPT.settingsSetURDescriptionWidth
    WMEURMPT.getId('urmpt-setting-mpdescriptionwidth').onkeypress = WMEURMPT.settingsSetMPDescriptionWidth
    WMEURMPT.getId('urmpt-setting-mpdescriptionwidth').onpaste = WMEURMPT.settingsSetMPDescriptionWidth
    WMEURMPT.getId('urmpt-setting-mpdescriptionwidth').oninput = WMEURMPT.settingsSetMPDescriptionWidth
    WMEURMPT.getId('urmpt-setting-mcsubjectwidth').onkeypress = WMEURMPT.settingsSetMCSubjectWidth
    WMEURMPT.getId('urmpt-setting-mcsubjectwidth').onpaste = WMEURMPT.settingsSetMCSubjectWidth
    WMEURMPT.getId('urmpt-setting-mcsubjectwidth').oninput = WMEURMPT.settingsSetMCSubjectWidth
    WMEURMPT.getId('urmpt-setting-mcbodywidth').onkeypress = WMEURMPT.settingsSetMCBodyWidth
    WMEURMPT.getId('urmpt-setting-mcbodywidth').onpaste = WMEURMPT.settingsSetMCBodyWidth
    WMEURMPT.getId('urmpt-setting-mcbodywidth').oninput = WMEURMPT.settingsSetMCBodyWidth
    WMEURMPT.getId('urmpt-setting-purcategorieswidth').onkeypress = WMEURMPT.settingsSetPURCategoriesWidth
    WMEURMPT.getId('urmpt-setting-purcategorieswidth').onpaste = WMEURMPT.settingsSetPURCategoriesWidth
    WMEURMPT.getId('urmpt-setting-purcategorieswidth').oninput = WMEURMPT.settingsSetPURCategoriesWidth
    WMEURMPT.getId('urmpt-setting-purnamewidth').onkeypress = WMEURMPT.settingsSetPURNameWidth
    WMEURMPT.getId('urmpt-setting-purnamewidth').onpaste = WMEURMPT.settingsSetPURNameWidth
    WMEURMPT.getId('urmpt-setting-purnamewidth').oninput = WMEURMPT.settingsSetPURNameWidth
    WMEURMPT.getId('urmpt-setting-urtaglist').onkeypress = WMEURMPT.settingsSetURTagList
    WMEURMPT.getId('urmpt-setting-urtaglist').onpaste = WMEURMPT.settingsSetURTagList
    WMEURMPT.getId('urmpt-setting-urtaglist').oninput = WMEURMPT.settingsSetURTagList
    WMEURMPT.getId('urmpt-setting-uragecolislastcomment').addEventListener('change', function (e) {
      WMEURMPT.URAgeColIsLastComment = e.target.checked
      WMEURMPT.saveOptions()
    })
    WMEURMPT.getId('urmpt-setting-disablescrolling').addEventListener('change', function (e) {
      WMEURMPT.disableScrolling = e.target.checked
      WMEURMPT.saveOptions()
      if (WMEURMPT.disableScrolling === false) {
        WMEURMPT.updateLongTextCrop()
      }
    })
    if (!WMEURMPT.disableScrolling === false) {
      WMEURMPT.updateLongTextCrop()
    }
    const cssElt = WMEURMPT.createElement('style')
    cssElt.type = 'text/css'
    let css = ''
    css += '.urt-table { border: 2px solid #3d3d3d; width: 290; }'
    css += '.urt-table tr { border: 1px solid #3d3d3d; }'
    css += '.urt-table tr td { border: 1px solid #3d3d3d; font-size: smaller; }'
    css += '.urt-table thead { border: 2px solid #3d3d3d; font-size: bigger; text-align: center; background-color: #93c4d3;}'
    css += '.urt-table-head-icon { height: 32px; vertical-align: middle; display: table-cell; }'
    css += '.urt-bg-pair { background-color: #93c4d3; }'
    css += '.urt-bg-highlighted { background-color: #c9e1e9; }'
    css += '.urt-bg-selected { background-color: #42FF9c; }'
    css += '.urt-bg-ifollow { background-color: #e0e0e0; }'
    css += '.urt-bg-odd { }'
    css += '.urt-bg-newcomments { background-color: #FFc90E; }'
    css += '.urt-filter-list { list-style-type: none; padding-left: 2px; overflow: hidden;}'
    css += '#urt-filterHideWithCommentCount { display: inline; height: 20px; font-size: smaller; }'
    css += '#urt-filterKW { display: inline; width: 30%; height: 20px; font-size: smaller; }'
    css += '#mct-filterKW { display: inline; width: 30%; height: 20px; font-size: smaller; }'
    css += '#purt-filterKW { display: inline; width: 30%; height: 20px; font-size: smaller; }'
    css += '#urt-filterLimitTo { display: inline; width: 30%; height: 20px; font-size: smaller; }'
    css += '#mpt-filterLimitTo { display: inline; width: 30%; height: 20px; font-size: smaller; }'
    css += '#mct-filterLimitTo { display: inline; width: 30%; height: 20px; font-size: smaller; }'
    css += '#purt-filterLimitTo { display: inline; width: 30%; height: 20px; font-size: smaller; }'
    css += '#urt-progressBarInfo { display: none; width: 90%; float: left; position: absolute; border-top-left-radius: 5px; border-top-right-radius: 5px; border-bottom-right-radius: 5px; border-bottom-left-radius: 5px; margin-bottom: -100%; background-color: #c9e1e9; z-index: 999; margin: 5px; margin-right: 20px; }'
    css += '.urt-progressBarBG { margin-top: 2px; margin-bottom: 2px; margin-left: 2px; margin-right: 2px; padding-bottom: 0px; padding-top: 0px; padding-left: 0px; padding-right: 0px; width: 33%; background-color: #93c4d3; border: 3px rgb(147, 196, 211); border-top-left-radius: 5px; border-top-right-radius: 5px; border-bottom-right-radius: 5px; border-bottom-left-radius: 5px; height: 22px;}'
    css += '.urt-progressBarFG { float: left; position: relative; bottom: 22px; height: 0px; text-align: center; width: 100% }'
    css += '#urt-info { margin: 5px; }'
    css += '.urt-blacklist { background: transparent url(data:image/png;base64,' + WMEURMPT.icon_blacklist + ') center top; background-size: 16px 16px; background-repeat: no-repeat; } '
    css += '#urmpt-qoptions { display: block; width: 100%; border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; border: 1px solid #dddddd; }'
    css += '.urt-chkbox { width: 16px; height: 16px; margin-top: -5px; }'
    cssElt.innerHTML = WMEURMPT.convertHtml(css)
    document.body.appendChild(cssElt)
    WMEURMPT.updateScanGroup()
    window.setInterval(WMEURMPT.save, 120000)
    if (WMEURMPT.isEnabled) {
      WMEURMPT.registerEvents()
      WMEURMPT.updateIHMFromURList()
      WMEURMPT.updateIHMFromMPList()
      WMEURMPT.updateIHMFromMCList()
      WMEURMPT.updateIHMFromPURList()
    }
    if (!WMEURMPT.isEnabled) {
      WMEURMPT.disable()
    }
  }

  WMEURMPT.setupCAEvents = function () {
    const tl = WMEURMPT.getId('urmpt-areas-fill-tl')
    const br = WMEURMPT.getId('urmpt-areas-fill-br')
    const add = WMEURMPT.getId('urmpt-areas-name-add')
    tl.onclick = WMEURMPT.getTLArea
    br.onclick = WMEURMPT.getBRArea
    add.onclick = WMEURMPT.addCustomAreaToFilterList
    const addFromPOI = WMEURMPT.getId('urmpt-areas-frompoi-add')
    addFromPOI.onclick = WMEURMPT.addCustomAreaFromPOIToFilterList
    const addFromWKT = WMEURMPT.getId('urmpt-areas-wktfile')
    addFromWKT.addEventListener('change', WMEURMPT.handleFileSelectAddFromWKT, false)
    const addFromWKTAdd = WMEURMPT.getId('urmpt-areas-wktfile-add')
    addFromWKTAdd.onclick = WMEURMPT.addCustomAreaFromWKTToFilterList
    const addFromJSON = WMEURMPT.getId('urmpt-areas-jsonfile')
    addFromJSON.addEventListener('change', WMEURMPT.handleFileSelectAddFromJSON, false)
    const addFromJSONAdd = WMEURMPT.getId('urmpt-areas-jsonfile-add')
    addFromJSONAdd.onclick = WMEURMPT.addCustomAreaFromJSONToFilterList
  }

  WMEURMPT.getTLArea = function () {
    const xy = WMEURMPT.wazeMap.getLonLatFromPixel({ x: 0, y: 0 })
    WMEURMPT.log('get TL', xy)
    WMEURMPT.getId('urmpt-areas-tl-lon').value = xy.lon
    WMEURMPT.getId('urmpt-areas-tl-lat').value = xy.lat
  }

  WMEURMPT.getBRArea = function () {
    const xy = WMEURMPT.wazeMap.getLonLatFromPixel({ x: WMEURMPT.wazeMap.getSize().w, y: WMEURMPT.wazeMap.getSize().h })
    WMEURMPT.log('get BR', xy)
    WMEURMPT.getId('urmpt-areas-br-lon').value = xy.lon
    WMEURMPT.getId('urmpt-areas-br-lat').value = xy.lat
  }

  WMEURMPT.closeLegend = function () {
    if (confirm('This legend will never be displayed anymore.' + NL + 'Are you sure you want to do that?')) {
      WMEURMPT.getId('urt-legend').style.display = 'none'
      WMEURMPT.getId('urt-close-legend').style.display = 'none'
      WMEURMPT.displayLegend = false
      WMEURMPT.log('Legend closed')
      WMEURMPT.saveOptions()
    }
  }

  WMEURMPT.connectURTabHandler = function () {
    WMEURMPT.getId('urmp-tabstitle-ur').onclick = WMEURMPT.updateIHMFromURList
  }

  WMEURMPT.connectMPTabHandler = function () {
    WMEURMPT.getId('urmp-tabstitle-mp').onclick = WMEURMPT.updateIHMFromMPList
  }

  WMEURMPT.connectMCTabHandler = function () {
    WMEURMPT.getId('urmp-tabstitle-mc').onclick = WMEURMPT.updateIHMFromMCList
  }

  WMEURMPT.connectPURTabHandler = function () {
    WMEURMPT.getId('urmp-tabstitle-pur').onclick = WMEURMPT.updateIHMFromPURList
  }

  WMEURMPT.enableOrDisable = function () {
    if (WMEURMPT.isEnabled) {
      WMEURMPT.getId('urmpt-onoff').innerHTML = WMEURMPT.convertHtml('<img class="urt-chkbox" src="data:image/png;base64,' + WMEURMPT.icon_unchecked + '" />')
      WMEURMPT.disable()
    } else {
      WMEURMPT.getId('urmpt-onoff').innerHTML = WMEURMPT.convertHtml('<img class="urt-chkbox" src="data:image/png;base64,' + WMEURMPT.icon_checked + '" />')
      WMEURMPT.enable()
    }
    WMEURMPT.isEnabled = !WMEURMPT.isEnabled
  }

  WMEURMPT.enable = function () {
    WMEURMPT.registerEvents()
    WMEURMPT.getId('urt-a-scanGroup').style.display = 'inline'
    WMEURMPT.getId('urmp-tabs').style.display = 'block'
    WMEURMPT.getId('urmpt-tab-content').style.display = 'block'
    WMEURMPT.getId('urmpt-qoptions').style.display = 'block'
    WMEURMPT.updateIHMFromURList()
    WMEURMPT.updateIHMFromMPList()
    WMEURMPT.updateIHMFromMCList()
    WMEURMPT.updateIHMFromPURList()
  }

  WMEURMPT.disable = function () {
    WMEURMPT.unregisterEvents()
    WMEURMPT.getId('urt-a-scanGroup').style.display = 'none'
    WMEURMPT.getId('urmp-tabs').style.display = 'none'
    WMEURMPT.getId('urmpt-tab-content').style.display = 'none'
    WMEURMPT.getId('urmpt-qoptions').style.display = 'none'
  }

  WMEURMPT.enableOrDisableDistance = function () {
    if (WMEURMPT.isComputeDistances) {
      WMEURMPT.getId('urmpt-donoff').innerHTML = WMEURMPT.convertHtml('<img class="urt-chkbox" src="data:image/png;base64,' + WMEURMPT.icon_unchecked + '" />')
    } else {
      WMEURMPT.getId('urmpt-donoff').innerHTML = WMEURMPT.convertHtml('<img class="urt-chkbox" src="data:image/png;base64,' + WMEURMPT.icon_checked + '" />')
    }
    WMEURMPT.isComputeDistances = !WMEURMPT.isComputeDistances
    WMEURMPT.saveOptions()
    if (WMEURMPT.isComputeDistances) {
      WMEURMPT.mapMoveEnd()
    }
  }

  WMEURMPT.enableOrDisableAutoScan = function () {
    if (WMEURMPT.isAutoScan) {
      WMEURMPT.getId('urmpt-asonoff').innerHTML = WMEURMPT.convertHtml('<img class="urt-chkbox" src="data:image/png;base64,' + WMEURMPT.icon_unchecked + '" />')
    } else {
      WMEURMPT.getId('urmpt-asonoff').innerHTML = WMEURMPT.convertHtml('<img class="urt-chkbox" src="data:image/png;base64,' + WMEURMPT.icon_checked + '" />')
    }
    WMEURMPT.isAutoScan = !WMEURMPT.isAutoScan
    WMEURMPT.saveOptions()
  }

  WMEURMPT.enableOrDisableScanUR = function () {
    if (WMEURMPT.scanUR) {
      WMEURMPT.getId('urmpt-suronoff').innerHTML = WMEURMPT.convertHtml('<img class="urt-chkbox" src="data:image/png;base64,' + WMEURMPT.icon_unchecked + '" />')
    } else {
      WMEURMPT.getId('urmpt-suronoff').innerHTML = WMEURMPT.convertHtml('<img class="urt-chkbox" src="data:image/png;base64,' + WMEURMPT.icon_checked + '" />')
    }
    WMEURMPT.scanUR = !WMEURMPT.scanUR
    WMEURMPT.saveOptions()
  }

  WMEURMPT.enableOrDisableScanMP = function () {
    if (WMEURMPT.scanMP) {
      WMEURMPT.getId('urmpt-smponoff').innerHTML = WMEURMPT.convertHtml('<img class="urt-chkbox" src="data:image/png;base64,' + WMEURMPT.icon_unchecked + '" />')
    } else {
      WMEURMPT.getId('urmpt-smponoff').innerHTML = WMEURMPT.convertHtml('<img class="urt-chkbox" src="data:image/png;base64,' + WMEURMPT.icon_checked + '" />')
    }
    WMEURMPT.scanMP = !WMEURMPT.scanMP
    WMEURMPT.saveOptions()
  }

  WMEURMPT.enableOrDisableScanMC = function () {
    if (WMEURMPT.scanMC) {
      WMEURMPT.getId('urmpt-smconoff').innerHTML = WMEURMPT.convertHtml('<img class="urt-chkbox" src="data:image/png;base64,' + WMEURMPT.icon_unchecked + '" />')
    } else {
      WMEURMPT.getId('urmpt-smconoff').innerHTML = WMEURMPT.convertHtml('<img class="urt-chkbox" src="data:image/png;base64,' + WMEURMPT.icon_checked + '" />')
    }
    WMEURMPT.scanMC = !WMEURMPT.scanMC
    WMEURMPT.saveOptions()
  }

  WMEURMPT.enableOrDisableScanPUR = function () {
    if (WMEURMPT.scanPUR) {
      WMEURMPT.getId('urmpt-spuronoff').innerHTML = WMEURMPT.convertHtml('<img class="urt-chkbox" src="data:image/png;base64,' + WMEURMPT.icon_unchecked + '" />')
    } else {
      WMEURMPT.getId('urmpt-spuronoff').innerHTML = WMEURMPT.convertHtml('<img class="urt-chkbox" src="data:image/png;base64,' + WMEURMPT.icon_checked + '" />')
    }
    WMEURMPT.scanPUR = !WMEURMPT.scanPUR
    WMEURMPT.saveOptions()
  }

  WMEURMPT.handleFileSelectAddFromWKT = function (evt) {
    const files = evt.target.files
    Array.from(files).forEach(f => {
      const reader = new FileReader()
      reader.onload = (function (theFile) {
        return function (e) {
          WMEURMPT.lastUploadedWKT = e.target.result
          WMEURMPT.log('import WKT file read')
        }
      }(f))
      reader.readAsText(f)
    })
  }

  WMEURMPT.showAreaInWKT = function (area) {
    let geometry = null
    for (let i = 0; i < WMEURMPT.areaList[area.type].length; i++) {
      if (WMEURMPT.areaList[area.type][i].name === area.name) {
        geometry = WMEURMPT.areaList[area.type][i].geometryWKT
        break
      }
    }
    if (geometry !== null) {
      this.setAttribute('download', area.name + '.wkt')
      this.href = 'data:application/octet-stream;charset=utf-8;base64,' + btoa(geometry)
    }
  }

  WMEURMPT.mapMoveEnd = function () {
    if (WMEURMPT.isComputeDistances) {
      WMEURMPT.mapCenterLonLat = OpenLayers.Layer.SphericalMercator.inverseMercator(WMEURMPT.wazeMap.olMap.center.lon, WMEURMPT.wazeMap.olMap.center.lat)
      for (let i = 0; i < WMEURMPT.URList.length; i++) {
        WMEURMPT.URList[i].updateDistanceToMapCenter()
      }
      for (let i = 0; i < WMEURMPT.MPList.length; i++) {
        WMEURMPT.MPList[i].updateDistanceToMapCenter()
      }
      for (let i = 0; i < WMEURMPT.MCList.length; i++) {
        WMEURMPT.MCList[i].updateDistanceToMapCenter()
      }
      for (let i = 0; i < WMEURMPT.PURList.length; i++) {
        WMEURMPT.PURList[i].updateDistanceToMapCenter()
      }
      WMEURMPT.updateIHMFromURList()
      WMEURMPT.updateIHMFromMPList()
      WMEURMPT.updateIHMFromMCList()
      WMEURMPT.updateIHMFromPURList()
    }
  }

  WMEURMPT.mapZoomEnd = function () {
    WMEURMPT.mapMoveEnd()
  }

  WMEURMPT.showPBInfo = function (show) {
    if (show) {
      WMEURMPT.getId('urt-progressBarInfo').style.display = 'block'
    } else {
      WMEURMPT.getId('urt-progressBarInfo').style.display = 'none'
    }
  }

  WMEURMPT.ProgressBar = function (div) {
    this.div = div
  }

  WMEURMPT.ProgressBar.prototype.isShown = function () {
    return this.div.style.display !== 'none'
  }

  WMEURMPT.ProgressBar.prototype.show = function () {
    this.div.style.display = 'block'
  }

  WMEURMPT.ProgressBar.prototype.hide = function () {
    this.div.style.display = 'none'
  }

  WMEURMPT.ProgressBar.prototype.update = function (value) {
    if (value === -1) {
      this.div.children[0].style.display = 'none'
      this.div.children[1].style.display = 'none'
      return
    }
    this.div.children[0].style.display = 'block'
    this.div.children[1].style.display = 'block'
    this.div.children[0].style.width = value + '%'
    this.div.children[1].innerHTML = WMEURMPT.convertHtml(value + '%')
  }

  WMEURMPT.clearAllUR = function () {
    WMEURMPT.URList = []
    WMEURMPT.URMap = {}
    WMEURMPT.log('UR list cleared')
    WMEURMPT.saveURList()
    WMEURMPT.updateIHMFromURList()
  }

  WMEURMPT.markAllURAsVisited = function () {
    for (let i = 0; i < WMEURMPT.URList.length; i++) {
      if (!WMEURMPT.isURFiltered(WMEURMPT.URList[i])) {
        WMEURMPT.URList[i].alreadyVisited = true
      }
    }
    WMEURMPT.log('All UR marked as visited')
    WMEURMPT.updateIHMFromURList()
  }

  WMEURMPT.blacklistUR = function (index) {
    const i = parseInt(index)
    if (i < 0 || i >= WMEURMPT.URList.length) {
      return
    }
    WMEURMPT.log((WMEURMPT.URList[i].blackListed ? 'Whitelist' : 'Blacklist') + ' UR: ' + WMEURMPT.URList[i].id)
    WMEURMPT.URList[i].blackListed = !WMEURMPT.URList[i].blackListed
    WMEURMPT.updateIHMFromURList()
  }

  WMEURMPT.URBlackListed = function (URId, value) {
    const ur = WMEURMPT.getURFromId(URId)
    if (ur != null) {
      WMEURMPT.log((value ? 'Blacklist' : 'Whitelist') + ' UR: ' + URId)
      ur.blackListed = value
    }
  }

  WMEURMPT.URVisited = function (URId) {
    const ur = WMEURMPT.getURFromId(URId)
    if (ur != null) {
      WMEURMPT.log('Mark UR ' + URId + ' as visited')
      ur.lastVisitCommentsCount = ur.data.session.comments.length
      ur.alreadyVisited = true
      WMEURMPT.updateIHMFromURList()
    }
  }

  WMEURMPT.getURFromId = function (id) {
    if (typeof WMEURMPT.URMap[id] === 'undefined') {
      return null
    }
    return WMEURMPT.URList[WMEURMPT.URMap[id]]
  }

  WMEURMPT.clearAllMP = function () {
    WMEURMPT.MPList = []
    WMEURMPT.MPMap = {}
    WMEURMPT.log('MP list cleared')
    WMEURMPT.saveMPList()
    WMEURMPT.updateIHMFromMPList()
  }

  WMEURMPT.markAllMPAsVisited = function () {
    for (let i = 0; i < WMEURMPT.MPList.length; i++) {
      if (!WMEURMPT.isMPFiltered(WMEURMPT.MPList[i])) {
        WMEURMPT.MPList[i].alreadyVisited = true
      }
    }
    WMEURMPT.log('All MP marked as visited')
    WMEURMPT.updateIHMFromMPList()
  }

  WMEURMPT.blacklistMP = function (index) {
    const i = parseInt(index)
    if (i < 0 || i >= WMEURMPT.MPList.length) {
      return
    }
    WMEURMPT.log((WMEURMPT.MPList[i].blackListed ? 'Whitelist' : 'Blacklist') + ' MP: ' + WMEURMPT.MPList[i].id)
    WMEURMPT.MPList[i].blackListed = !WMEURMPT.MPList[i].blackListed
    WMEURMPT.updateIHMFromMPList()
  }

  WMEURMPT.MPVisited = function (MPId) {
    const mp = WMEURMPT.getMPFromId(MPId)
    if (mp != null) {
      WMEURMPT.log('Mark MP ' + MPId + ' as visited')
      mp.alreadyVisited = true
      WMEURMPT.updateIHMFromMPList()
    }
  }

  WMEURMPT.getMPFromId = function (id) {
    if (typeof WMEURMPT.MPMap[id] === 'undefined') {
      return null
    }
    return WMEURMPT.MPList[WMEURMPT.MPMap[id]]
  }

  WMEURMPT.clearAllMC = function () {
    WMEURMPT.MCList = []
    WMEURMPT.MCMap = {}
    WMEURMPT.log('MC list cleared')
    WMEURMPT.saveMCList()
    WMEURMPT.updateIHMFromMCList()
  }

  WMEURMPT.markAllMCAsVisited = function () {
    for (let i = 0; i < WMEURMPT.MCList.length; i++) {
      if (!WMEURMPT.isMCFiltered(WMEURMPT.MCList[i])) {
        WMEURMPT.MCList[i].alreadyVisited = true
      }
    }
    WMEURMPT.log('All MC marked as visited')
    WMEURMPT.updateIHMFromMCList()
  }

  WMEURMPT.blacklistMC = function (index) {
    const i = parseInt(index)
    if (i < 0 || i >= WMEURMPT.MCList.length) {
      return
    }
    WMEURMPT.log((WMEURMPT.MCList[i].blackListed ? 'Whitelist' : 'Blacklist') + ' MC: ' + WMEURMPT.MCList[i].id)
    WMEURMPT.MCList[i].blackListed = !WMEURMPT.MCList[i].blackListed
    WMEURMPT.updateIHMFromMCList()
  }

  WMEURMPT.MCBlackListed = function (MCId, value) {
    const mc = WMEURMPT.getMCFromId(MCId)
    if (mc != null) {
      WMEURMPT.log((value ? 'Blacklist' : 'Whitelist') + ' MC: ' + MCId)
      mc.blackListed = value
    }
  }

  WMEURMPT.MCVisited = function (MCId) {
    const mc = WMEURMPT.getMCFromId(MCId)
    if (mc != null) {
      WMEURMPT.log('Mark MC ' + MCId + ' as visited')
      mc.lastVisitCommentsCount = Object.prototype.hasOwnProperty.call(mc.data, 'conversation') ? mc.data.conversation.length : 0
      mc.alreadyVisited = true
      WMEURMPT.updateIHMFromMCList()
    }
  }

  WMEURMPT.getMCFromId = function (id) {
    if (typeof WMEURMPT.MCMap[id] === 'undefined') {
      return null
    }
    return WMEURMPT.MCList[WMEURMPT.MCMap[id]]
  }

  WMEURMPT.clearAllPUR = function () {
    WMEURMPT.PURList = []
    WMEURMPT.PURMap = {}
    WMEURMPT.log('PUR list cleared')
    WMEURMPT.savePURList()
    WMEURMPT.updateIHMFromPURList()
  }

  WMEURMPT.markAllPURAsVisited = function () {
    for (let i = 0; i < WMEURMPT.PURList.length; i++) {
      if (!WMEURMPT.isPURFiltered(WMEURMPT.PURList[i])) {
        WMEURMPT.PURList[i].alreadyVisited = true
      }
    }
    WMEURMPT.log('All PUR marked as visited')
    WMEURMPT.updateIHMFromPURList()
  }

  WMEURMPT.blacklistPUR = function (index) {
    const i = parseInt(index)
    if (i < 0 || i >= WMEURMPT.PURList.length) {
      return
    }
    WMEURMPT.log((WMEURMPT.PURList[i].blackListed ? 'Whitelist' : 'Blacklist') + ' PUR: ' + WMEURMPT.PURList[i].id)
    WMEURMPT.PURList[i].blackListed = !WMEURMPT.PURList[i].blackListed
    WMEURMPT.updateIHMFromPURList()
  }

  WMEURMPT.PURVisited = function (PURId) {
    const pur = WMEURMPT.getPURFromId(PURId)
    if (pur != null) {
      WMEURMPT.log('Mark PUR ' + PURId + ' as visited')
      pur.alreadyVisited = true
      WMEURMPT.updateIHMFromPURList()
    }
  }

  WMEURMPT.getPURFromId = function (id) {
    if (typeof WMEURMPT.PURMap[id] === 'undefined') {
      return null
    }
    return WMEURMPT.PURList[WMEURMPT.PURMap[id]]
  }

  WMEURMPT.getHRURResolutionFromType = function (type) {
    if (type === 1) {
      return 'Not identified'
    }
    if (type === 0) {
      return 'Solved'
    }
  }

  WMEURMPT.getFullURTypeFromType = function (type) {
    return I18n.translations[I18n.locale].update_requests.types[type]
  }

  WMEURMPT.getHRURTypeFromType = function (type) {
    switch (type) {
      case 6:
        return '<span title="' + WMEURMPT.getFullURTypeFromType(type) + '" style="display: block; width: 100%;">IT</span>'
      case 7:
        return '<span title="' + WMEURMPT.getFullURTypeFromType(type) + '" style="display: block; width: 100%;">IA</span>'
      case 8:
        return '<span title="' + WMEURMPT.getFullURTypeFromType(type) + '" style="display: block; width: 100%;">IR</span>'
      case 9:
        return '<span title="' + WMEURMPT.getFullURTypeFromType(type) + '" style="display: block; width: 100%;">MRa</span>'
      case 10:
        return '<span title="' + WMEURMPT.getFullURTypeFromType(type) + '" style="display: block; width: 100%;">GE</span>'
      case 11:
        return '<span title="' + WMEURMPT.getFullURTypeFromType(type) + '" style="display: block; width: 100%;">TnA</span>'
      case 12:
        return '<span title="' + WMEURMPT.getFullURTypeFromType(type) + '" style="display: block; width: 100%;">IJ</span>'
      case 13:
        return '<span title="' + WMEURMPT.getFullURTypeFromType(type) + '" style="display: block; width: 100%;">MBO</span>'
      case 14:
        return '<span title="' + WMEURMPT.getFullURTypeFromType(type) + '" style="display: block; width: 100%;">WDD</span>'
      case 15:
        return '<span title="' + WMEURMPT.getFullURTypeFromType(type) + '" style="display: block; width: 100%;">ME</span>'
      case 16:
        return '<span title="' + WMEURMPT.getFullURTypeFromType(type) + '" style="display: block; width: 100%;">MR</span>'
      case 18:
        return '<span title="' + WMEURMPT.getFullURTypeFromType(type) + '" style="display: block; width: 100%;">ML</span>'
      case 19:
        return '<span title="' + WMEURMPT.getFullURTypeFromType(type) + '" style="display: block; width: 100%;">BR</span>'
      case 21:
        return '<span title="' + WMEURMPT.getFullURTypeFromType(type) + '" style="display: block; width: 100%;">MSN</span>'
      case 22:
        return '<span title="' + WMEURMPT.getFullURTypeFromType(type) + '" style="display: block; width: 100%;">MSS</span>'
      case 23:
        return '<span title="' + WMEURMPT.getFullURTypeFromType(type) + '" style="display: block; width: 100%;">MSL</span>'
      default:
        return (WMEURMPT.getFullURTypeFromType(type) + ' ').replace(/([A-Za-z])[A-Za-z]* /g, '$1').toUpperCase().substring(0, 3)
    }
  }

  WMEURMPT.getFullMPTypeFromType = function (type) {
    return I18n.translations[I18n.locale].problems.types[type].title
  }

  WMEURMPT.getHRMPTypeFromType = function (type) {
    return '<span title="' + I18n.translations[I18n.locale].problems.types[type].title + '" style="display: block; width: 100%;">P</span>'
  }

  WMEURMPT.getHRMPDescriptionFromType = function (type) {
    switch (type) {
      case 1:
        return '<span title="' + WMEURMPT.getFullMPTypeFromType(type) + '" style="display: block; width: 100%;">Crooked segment</span>'
      case 17:
        return '<span title="' + WMEURMPT.getFullMPTypeFromType(type) + '" style="display: block; width: 100%;">Segment without details</span>'
      case 50:
        return '<span title="' + WMEURMPT.getFullMPTypeFromType(type) + '" style="display: block; width: 100%;">Parking Lot as point</span>'
      case 101:
        return '<span title="' + WMEURMPT.getFullMPTypeFromType(type) + '" style="display: block; width: 100%;">Driving dr m/match</span>'
      case 102:
        return '<span title="' + WMEURMPT.getFullMPTypeFromType(type) + '" style="display: block; width: 100%;">Missing junction</span>'
      case 103:
        return '<span title="' + WMEURMPT.getFullMPTypeFromType(type) + '" style="display: block; width: 100%;">Missing road</span>'
      case 104:
        return '<span title="' + WMEURMPT.getFullMPTypeFromType(type) + '" style="display: block; width: 100%;">Cross rd junc miss</span>'
      case 105:
        return '<span title="' + WMEURMPT.getFullMPTypeFromType(type) + '" style="display: block; width: 100%;">Road type mismatch</span>'
      case 106:
        return '<span title="' + WMEURMPT.getFullMPTypeFromType(type) + '" style="display: block; width: 100%;">Rst trn m. be alwd</span>'
      case 200:
        return '<span title="' + WMEURMPT.getFullMPTypeFromType(type) + '" style="display: block; width: 100%;">Turn problem</span>'
      case 300:
        return '<span title="' + WMEURMPT.getFullMPTypeFromType(type) + '" style="display: block; width: 100%;">Road closure</span>'
      default:
        return '<span title="' + I18n.translations[I18n.locale].problems.types[type].title + '" style="display: block; width: 100%;">' + I18n.translations[I18n.locale].problems.types[type].title + '</span>'
    }
  }

  WMEURMPT.getFullPURTypeFromType = function (type) {
    WMEURMPT.log('getType:', type)
    WMEURMPT.log('I18n.translations[' + I18n.locale + '].venues.update_requests.panel.title:', I18n.translations[I18n.locale].venues.update_requests.panel.title)
    return I18n.translations[I18n.locale].venues.update_requests.panel.title[type]
  }

  WMEURMPT.getPURCategoriesFromCategories = function (cat) {
    return I18n.translations[I18n.locale].venues.categories[cat]
  }

  WMEURMPT.getFullPURCategoriesFromCategories = function () {
    return I18n.translations[I18n.locale].venues.categories
  }

  WMEURMPT.compareUR = function (a, b, i) {
    if (arguments.length === 2) {
      i = 0
    }
    if (i >= WMEURMPT.sortHistoryUR.length) {
      return 0
    }

    let da = -1
    let db = -1

    switch (WMEURMPT.sortHistoryUR[i]) {
      case WMEURMPT.sortModeListUR.ageDSC:
        if (a.data.driveDate === b.data.driveDate) {
          return WMEURMPT.compareUR(a, b, i + 1)
        }
        return a.data.driveDate - b.data.driveDate
      case WMEURMPT.sortModeListUR.ageASC:
        if (a.data.driveDate === b.data.driveDate) {
          return WMEURMPT.compareUR(a, b, i + 1)
        }
        return b.data.driveDate - a.data.driveDate
      case WMEURMPT.sortModeListUR.typeDSC:
        if (a.data.type === b.data.type) {
          return WMEURMPT.compareUR(a, b, i + 1)
        }
        return a.data.type - b.data.type
      case WMEURMPT.sortModeListUR.typeASC:
        if (a.data.type === b.data.type) {
          return WMEURMPT.compareUR(a, b, i + 1)
        }
        return b.data.type - a.data.type
      case WMEURMPT.sortModeListUR.commentCountDSC:
        if (a.data.session.comments.length === b.data.session.comments.length) {
          return WMEURMPT.compareUR(a, b, i + 1)
        }
        return a.data.session.comments.length - b.data.session.comments.length
      case WMEURMPT.sortModeListUR.commentCountASC:
        if (a.data.session.comments.length === b.data.session.comments.length) {
          return WMEURMPT.compareUR(a, b, i + 1)
        }
        return b.data.session.comments.length - a.data.session.comments.length
      case WMEURMPT.sortModeListUR.distanceDSC:
        if (a.distanceToMapCenter === b.distanceToMapCenter) {
          return WMEURMPT.compareUR(a, b, i + 1)
        }
        return a.distanceToMapCenter - b.distanceToMapCenter
      case WMEURMPT.sortModeListUR.distanceASC:
        if (a.distanceToMapCenter === b.distanceToMapCenter) {
          return WMEURMPT.compareUR(a, b, i + 1)
        }
        return b.distanceToMapCenter - a.distanceToMapCenter
      case WMEURMPT.sortModeListUR.lastCommentDSC:
        da = a.data.driveDate
        db = b.data.driveDate
        if (a.data.session.comments.length !== 0) {
          da = a.data.session.comments[a.data.session.comments.length - 1].createdOn
        }
        if (b.data.session.comments.length !== 0) {
          db = b.data.session.comments[b.data.session.comments.length - 1].createdOn
        }
        if (a.data.session.comments.length !== 0 && b.data.session.comments.length === 0) {
          return -1
        }
        if (a.data.session.comments.length === 0 && b.data.session.comments.length !== 0) {
          return 1
        }
        if (da === db) {
          return WMEURMPT.compareUR(a, b, i + 1)
        }
        return da - db
      case WMEURMPT.sortModeListUR.lastCommentASC:
        da = a.data.driveDate
        db = b.data.driveDate
        if (a.data.session.comments.length !== 0) {
          da = a.data.session.comments[a.data.session.comments.length - 1].createdOn
        }
        if (b.data.session.comments.length !== 0) {
          db = b.data.session.comments[b.data.session.comments.length - 1].createdOn
        }
        if (a.data.session.comments.length !== 0 && b.data.session.comments.length === 0) {
          return 1
        }
        if (a.data.session.comments.length === 0 && b.data.session.comments.length !== 0) {
          return -1
        }
        if (da === db) {
          return WMEURMPT.compareUR(a, b, i + 1)
        }
        return db - da
    }
    return 0
  }

  WMEURMPT.compareMP = function (a, b, i) {
    if (arguments.length === 2) {
      i = 0
    }
    if (i >= WMEURMPT.sortHistoryMP.length) {
      return 0
    }
    switch (WMEURMPT.sortHistoryMP[i]) {
      case WMEURMPT.sortModeListMP.priorityDSC:
        if (a.data.weight === b.data.weight) {
          return WMEURMPT.compareMP(a, b, i + 1)
        }
        return a.data.weight - b.data.weight
      case WMEURMPT.sortModeListMP.priorityASC:
        if (a.data.weight === b.data.weight) {
          return WMEURMPT.compareMP(a, b, i + 1)
        }
        return b.data.weight - a.data.weight
      case WMEURMPT.sortModeListMP.typeDSC:
        if (a.data.subType === b.data.subType) {
          return WMEURMPT.compareMP(a, b, i + 1)
        }
        return a.data.subType - b.data.subType
      case WMEURMPT.sortModeListMP.typeASC:
        if (a.data.subType === b.data.subType) {
          return WMEURMPT.compareMP(a, b, i + 1)
        }
        return b.data.subType - a.data.subType
      case WMEURMPT.sortModeListMP.distanceDSC:
        if (a.distanceToMapCenter === b.distanceToMapCenter) {
          return WMEURMPT.compareMP(a, b, i + 1)
        }
        return a.distanceToMapCenter - b.distanceToMapCenter
      case WMEURMPT.sortModeListMP.distanceASC:
        if (a.distanceToMapCenter === b.distanceToMapCenter) {
          return WMEURMPT.compareMP(a, b, i + 1)
        }
        return b.distanceToMapCenter - a.distanceToMapCenter
    }
    return 0
  }

  WMEURMPT.compareMC = function (a, b, i) {
    if (arguments.length === 2) {
      i = 0
    }
    if (i >= WMEURMPT.sortHistoryMC.length) {
      return 0
    }

    let acount = 0
    let bcount = 0

    switch (WMEURMPT.sortHistoryMC[i]) {
      case WMEURMPT.sortModeListMC.ageDSC:
        if (a.data.createdOn === b.data.createdOn) {
          return WMEURMPT.compareMC(a, b, i + 1)
        }
        return a.data.createdOn - b.data.createdOn
      case WMEURMPT.sortModeListMC.ageASC:
        if (a.data.createdOn === b.data.createdOn) {
          return WMEURMPT.compareMC(a, b, i + 1)
        }
        return b.data.createdOn - a.data.createdOn
      case WMEURMPT.sortModeListMC.distanceDSC:
        if (a.distanceToMapCenter === b.distanceToMapCenter) {
          return WMEURMPT.compareMC(a, b, i + 1)
        }
        return a.distanceToMapCenter - b.distanceToMapCenter
      case WMEURMPT.sortModeListMC.distanceASC:
        if (a.distanceToMapCenter === b.distanceToMapCenter) {
          return WMEURMPT.compareMC(a, b, i + 1)
        }
        return b.distanceToMapCenter - a.distanceToMapCenter
      case WMEURMPT.sortModeListMC.commentCountDSC:
        acount = Object.prototype.hasOwnProperty.call(a.data, 'conversation') ? a.data.conversation.length : 0
        bcount = Object.prototype.hasOwnProperty.call(b.data, 'conversation') ? b.data.conversation.length : 0
        if (acount === bcount) {
          return WMEURMPT.compareMC(a, b, i + 1)
        }
        return acount - bcount
      case WMEURMPT.sortModeListMC.commentCountASC:
        acount = Object.prototype.hasOwnProperty.call(a.data, 'conversation') ? a.data.conversation.length : 0
        bcount = Object.prototype.hasOwnProperty.call(b.data, 'conversation') ? b.data.conversation.length : 0
        if (acount === bcount) {
          return WMEURMPT.compareMC(a, b, i + 1)
        }
        return bcount - acount
    }
    return 0
  }

  WMEURMPT.comparePUR = function (a, b, i) {
    if (arguments.length === 2) {
      i = 0
    }
    if (i >= WMEURMPT.sortHistoryPUR.length) {
      return 0
    }
    switch (WMEURMPT.sortHistoryPUR[i]) {
      case WMEURMPT.sortModeListPUR.ageDSC:
        if (a.data.dateAddedMin === b.data.dateAddedMin) {
          return WMEURMPT.comparePUR(a, b, i + 1)
        }
        return a.data.dateAddedMin - b.data.dateAddedMin
      case WMEURMPT.sortModeListPUR.ageASC:
        if (a.data.dateAddedMin === b.data.dateAddedMin) {
          return WMEURMPT.comparePUR(a, b, i + 1)
        }
        return b.data.dateAddedMin - a.data.dateAddedMin
      case WMEURMPT.sortModeListPUR.categoriesDSC:
      {
        let categoriesA = ''
        for (let n = 0; n < a.data.categories.length; n++) {
          categoriesA += WMEURMPT.getPURCategoriesFromCategories(a.data.categories[n]) + ' '
        }
        let categoriesB = ''
        for (let n = 0; n < b.data.categories.length; n++) {
          categoriesB += WMEURMPT.getPURCategoriesFromCategories(b.data.categories[n]) + ' '
        }
        if (categoriesA.toUpperCase() < categoriesB.toUpperCase()) {
          return -1
        } else if (categoriesA.toUpperCase() > categoriesB.toUpperCase()) {
          return 1
        } else {
          return WMEURMPT.comparePUR(a, b, i + 1)
        }
      }
      case WMEURMPT.sortModeListPUR.categoriesASC:
      {
        let categoriesA = ''
        for (let n = 0; n < a.data.categories.length; n++) {
          categoriesA += WMEURMPT.getPURCategoriesFromCategories(a.data.categories[n]) + ' '
        }
        let categoriesB = ''
        for (let n = 0; n < b.data.categories.length; n++) {
          categoriesB += WMEURMPT.getPURCategoriesFromCategories(b.data.categories[n]) + ' '
        }
        if (categoriesA.toUpperCase() > categoriesB.toUpperCase()) {
          return -1
        } else if (categoriesA.toUpperCase() < categoriesB.toUpperCase()) {
          return 1
        } else {
          return WMEURMPT.comparePUR(a, b, i + 1)
        }
      }
      case WMEURMPT.sortModeListPUR.nameDSC:
      {
        const nameA = a.data.name; const nameB = b.data.name
        if (nameA.toUpperCase() < nameB.toUpperCase()) {
          return -1
        } else if (nameA.toUpperCase() > nameB.toUpperCase()) {
          return 1
        } else {
          return WMEURMPT.comparePUR(a, b, i + 1)
        }
      }
      case WMEURMPT.sortModeListPUR.nameASC:
      {
        const nameA = a.data.name; const nameB = b.data.name
        if (nameA.toUpperCase() > nameB.toUpperCase()) {
          return -1
        } else if (nameA.toUpperCase() < nameB.toUpperCase()) {
          return 1
        } else {
          return WMEURMPT.comparePUR(a, b, i + 1)
        }
      }
      case WMEURMPT.sortModeListPUR.distanceDSC:
        if (a.distanceToMapCenter === b.distanceToMapCenter) {
          return WMEURMPT.comparePUR(a, b, i + 1)
        }
        return a.distanceToMapCenter - b.distanceToMapCenter
      case WMEURMPT.sortModeListPUR.distanceASC:
        if (a.distanceToMapCenter === b.distanceToMapCenter) {
          return WMEURMPT.comparePUR(a, b, i + 1)
        }
        return b.distanceToMapCenter - a.distanceToMapCenter
      case WMEURMPT.sortModeListPUR.nbpurDSC:
        if (a.data.venueUpdateRequests.length === b.data.venueUpdateRequests.length) {
          return WMEURMPT.comparePUR(a, b, i + 1)
        }
        return a.data.venueUpdateRequests.length - b.data.venueUpdateRequests.length
      case WMEURMPT.sortModeListPUR.nbpurASC:
        if (a.data.venueUpdateRequests.length === b.data.venueUpdateRequests.length) {
          return WMEURMPT.comparePUR(a, b, i + 1)
        }
        return b.data.venueUpdateRequests.length - a.data.venueUpdateRequests.length
    }
    return 0
  }

  WMEURMPT.compareURDriveDate = function (a, b) {
    if (a.data.driveDate === b.data.driveDate) {
      return WMEURMPT.compareURType(a, b)
    }
    return a.data.driveDate - b.data.driveDate
  }

  WMEURMPT.compareMPPriority = function (a, b) {
    if (a.data.weight === b.data.weight) {
      return WMEURMPT.compareMPType(a, b)
    }
    return a.data.weight - b.data.weight
  }

  WMEURMPT.compareURType = function (a, b) {
    if (a.data.type === b.data.type) {
      return WMEURMPT.compareURCommentCount(a, b)
    }
    return a.data.type - b.data.type
  }

  WMEURMPT.compareMPType = function (a, b) {
    if (a.data.subType === b.data.subType) {
      return WMEURMPT.compareURMPDistanceToMapCenter(a, b)
    }
    return a.data.subType - b.data.subType
  }

  WMEURMPT.compareURCommentCount = function (a, b) {
    if (a.data.session.comments.length === b.data.session.comments.length) {
      return WMEURMPT.compareURMPDistanceToMapCenter(a, b)
    }
    return a.data.session.comments.length - b.data.session.comments.length
  }

  WMEURMPT.compareURMPDistanceToMapCenter = function (a, b) {
    if (a.distanceToMapCenter === b.distanceToMapCenter) {
      return a.id - b.id
    }
    return a.distanceToMapCenter - b.distanceToMapCenter
  }

  WMEURMPT.compareURLastCommentDate = function (a, b) {
    let da = a.data.driveDate
    let db = b.data.driveDate
    if (a.data.session.comments.length !== 0) {
      da = a.data.session.comments[a.data.session.comments.length - 1].createdOn
    }
    if (b.data.session.comments.length !== 0) {
      db = b.data.session.comments[b.data.session.comments.length - 1].createdOn
    }
    if (a.data.session.comments.length !== 0 && b.data.session.comments.length === 0) {
      return -1
    }
    if (a.data.session.comments.length === 0 && b.data.session.comments.length !== 0) {
      return 1
    }
    if (da === db) {
      return WMEURMPT.compareURType(a, b)
    }
    return da - db
  }

  WMEURMPT.changeTableURSortTo = function (sortMode) {
    sortMode = parseInt(sortMode)
    const pos = WMEURMPT.sortHistoryUR.indexOf(sortMode)
    if (pos !== -1) {
      WMEURMPT.sortHistoryUR.splice(pos)
    }
    if (WMEURMPT.sortHistoryUR[0] === -sortMode) {
      WMEURMPT.sortHistoryUR[0] = sortMode
    } else {
      WMEURMPT.sortHistoryUR.splice(0, 0, sortMode)
    }
    WMEURMPT.updateIHMFromURList(sortMode)
  }

  WMEURMPT.changeTableMPSortTo = function (sortMode) {
    sortMode = parseInt(sortMode)
    const pos = WMEURMPT.sortHistoryMP.indexOf(sortMode)
    if (pos !== -1) {
      WMEURMPT.sortHistoryMP.splice(pos)
    }
    if (WMEURMPT.sortHistoryMP[0] === -sortMode) {
      WMEURMPT.sortHistoryMP[0] = sortMode
    } else {
      WMEURMPT.sortHistoryMP.splice(0, 0, sortMode)
    }
    WMEURMPT.updateIHMFromMPList(sortMode)
  }

  WMEURMPT.changeTableMCSortTo = function (sortMode) {
    sortMode = parseInt(sortMode)
    const pos = WMEURMPT.sortHistoryMC.indexOf(sortMode)
    if (pos !== -1) {
      WMEURMPT.sortHistoryMC.splice(pos)
    }
    if (WMEURMPT.sortHistoryMC[0] === -sortMode) {
      WMEURMPT.sortHistoryMC[0] = sortMode
    } else {
      WMEURMPT.sortHistoryMC.splice(0, 0, sortMode)
    }
    WMEURMPT.updateIHMFromMCList(sortMode)
  }

  WMEURMPT.changeTablePURSortTo = function (sortMode) {
    sortMode = parseInt(sortMode)
    const pos = WMEURMPT.sortHistoryPUR.indexOf(sortMode)
    if (pos !== -1) {
      WMEURMPT.sortHistoryPUR.splice(pos)
    }
    if (WMEURMPT.sortHistoryPUR[0] === -sortMode) {
      WMEURMPT.sortHistoryPUR[0] = sortMode
    } else {
      WMEURMPT.sortHistoryPUR.splice(0, 0, sortMode)
    }
    WMEURMPT.logDebug('sort history:', WMEURMPT.sortHistoryPUR)
    WMEURMPT.updateIHMFromPURList(sortMode)
  }

  WMEURMPT.getColorFromAge = function (ageInDays) {
    const r = 255
    let g = 0
    let b = 255
    if (ageInDays < 15) {
      b = 0
      g = 255 - ageInDays * 17
    } else if (ageInDays < 30) {
      b = (ageInDays - 15) * 17
    }
    if (g < 0) {
      g = 0
    }
    if (b > 255) {
      b = 255
    }
    return '#' + WMEURMPT.decimalToHex(r, 2) + WMEURMPT.decimalToHex(g, 2) + WMEURMPT.decimalToHex(b, 2)
  }

  WMEURMPT.getColorFromWieght = function (MPWeight) {
    let r = 255
    let g = 0
    let b = 255
    if (MPWeight === 2) {
      r = 255
      b = 0
    } else if (MPWeight === 3) {
      g = 255
      b = 0
    } else if (MPWeight > 3) {
      r = 0
      g = 255
      b = 0
    }
    return '#' + WMEURMPT.decimalToHex(r, 2) + WMEURMPT.decimalToHex(g, 2) + WMEURMPT.decimalToHex(b, 2)
  }

  WMEURMPT.getColorFromStartTime = function (ts) {
    const aDate = new Date()
    const now = aDate.getTime()
    let deltaH = (ts - now) / 3600000
    let r = 255
    let g = 0
    let b = 255
    if (deltaH < 0) {
      return '#' + WMEURMPT.decimalToHex(r, 2) + WMEURMPT.decimalToHex(g, 2) + WMEURMPT.decimalToHex(b, 2)
    }
    r = 0
    g = 255
    b = 0
    if (deltaH > 30 * 24) {
      return '#' + WMEURMPT.decimalToHex(r, 2) + WMEURMPT.decimalToHex(g, 2) + WMEURMPT.decimalToHex(b, 2)
    }
    r = 255
    g = 0
    b = 255
    if (deltaH < 7 * 24) {
      b = Math.floor(255 - deltaH / (7 * 24) * 255)
    } else {
      if (deltaH < 17 * 24) {
        deltaH = deltaH - 7 * 24
        b = 0
        g = Math.floor(255 - deltaH / (10 * 24) * 255)
      } else {
        deltaH = deltaH - 17 * 24
        g = 255
        b = 0
        r = Math.floor(255 - deltaH / (13 * 24) * 255)
      }
    }
    if (b > 255) {
      b = 255
    }
    if (r > 255) {
      r = 255
    }
    if (g > 255) {
      g = 255
    }
    return '#' + WMEURMPT.decimalToHex(r, 2) + WMEURMPT.decimalToHex(g, 2) + WMEURMPT.decimalToHex(b, 2)
  }

  WMEURMPT.updateIHMFromURList = function (sortMode) {
    const div = WMEURMPT.getId('urt-list')
    if (WMEURMPT.URList.length === 0) {
      WMEURMPT.removeChildElements(div)
      div.innerHTML = WMEURMPT.convertHtml('')
      return
    }
    sortMode = typeof sortMode !== 'undefined' && sortMode != null ? sortMode : WMEURMPT.currentSortModeUR
    if (sortMode !== WMEURMPT.currentSortModeUR) {
      WMEURMPT.URList.sort(WMEURMPT.compareUR)
      WMEURMPT.URMap = WMEURMPT.listToObject(WMEURMPT.URList)
    }
    WMEURMPT.currentSortModeUR = sortMode
    let content = ''
    content += '<table id="urmpt-ur-table" class="urt-table">'
    content += '<thead><tr>'
    content += '<td><div class="urt-table-head-icon"><img style="width: 16px" title="Blacklist UR 1 by 1." src="data:image/png;base64,' + WMEURMPT.icon_blacklist + '" /></div></td>'
    content += '<td><div class="urt-table-head-icon"><a href="#" id="urt-table-sort-age"><img style="width: 16px" title="Age of the UR.' + NL + 'Click to sort." src="data:image/png;base64,' + WMEURMPT.icon_age + '" /></a><a href="#" id="urt-table-sort-lastcomment" style="font-size: 1.5em;" class="w-icon w-icon-chat"></a></div></td>'
    content += '<td><div class="urt-table-head-icon"><a href="#" id="urt-table-sort-type"><img title="Type of the UR.' + NL + 'Click to sort." src="data:image/png;base64,' + WMEURMPT.icon_type + '" /></a></div></td>'
    content += '<td title="Description" style="max-width:' + WMEURMPT.URDescriptionMaxLength + 'ch; overflow: hidden; white-space: nowrap; text-overflow: ellipsis;">Description</td>'
    content += '<td><div class="urt-table-head-icon"><a href="#" id="urt-table-sort-ccount" style="font-size: 1.5em;" class="w-icon w-icon-chat"></a></div></td>'
    content += '<td><div class="urt-table-head-icon"><a href="#" id="urt-table-sort-distance"><img title="Distance to the center of the map.' + NL + 'Click to sort." src="data:image/png;base64,' + WMEURMPT.icon_distance + '" /></a></div></td>'
    content += '<td style="width: 20px; display: inline-block; border: none;"><center><div class="urt-table-head-icon"><i class="fa fa-crosshairs crosshair icon-screenshot"></i></div></center></td>'
    content += '</tr></thead>'
    let displayedURCount = 0
    let hiddenURCount = 0
    for (let i = 0; i < WMEURMPT.URList.length; i++) {
      if (WMEURMPT.getId('urt-checkbox-filterHideLimitTo').checked) {
        if (displayedURCount >= WMEURMPT.currentURLimitTo) {
          hiddenURCount += WMEURMPT.URList.length - i
          break
        }
      }
      if (WMEURMPT.isURFiltered(WMEURMPT.URList[i])) {
        hiddenURCount++
        continue
      }
      displayedURCount++
      const URDays = WMEURMPT.getDuration(WMEURMPT.URList[i].data.driveDate)
      const distance = WMEURMPT.URList[i].distanceToMapCenter
      let distanceStr = ''
      if (W.prefs.get('isImperial')) {
        distanceStr = Math.floor(distance * 3.28084) + '&nbsp;<font size: smaller>ft</font>'
        if (distance * 3.28084 >= 1000) {
          distanceStr = Math.floor(distance * 0.000621371) + '&nbsp;<font size: smaller>mi</font>'
        }
      } else {
        distanceStr = Math.floor(distance) + '&nbsp;<font size: smaller>m</font>'
        if (distance >= 1000) {
          distanceStr = Math.floor(distance / 1000) + '&nbsp;<font size: smaller>km</font>'
        }
        if (distance >= 1000000) {
          distanceStr = Math.floor(distance / 1000000) + '&nbsp;<font size: smaller>Mm</font>'
        }
      }
      let comments = ''
      let lastCommentDays = null
      for (let c = 0; c < WMEURMPT.URList[i].data.session.comments.length; c++) {
        comments += WMEURMPT.URList[i].data.session.comments[c].userName + ' (' + (new Date(WMEURMPT.URList[i].data.session.comments[c].createdOn)).toLocaleString() + '):' + NL
        comments += WMEURMPT.URList[i].data.session.comments[c].text + NL + NL
        lastCommentDays = WMEURMPT.getDuration(WMEURMPT.URList[i].data.session.comments[c].createdOn)
        if (c === WMEURMPT.URList[i].data.session.comments.length - 1 && WMEURMPT.URList[i].data.session.comments[c].userName === WMEURMPT.me.getUsername()) {
          WMEURMPT.URList[i].lastVisitCommentsCount = WMEURMPT.URList[i].data.session.comments.length
        }
      }
      content += '<tr id="urt-tr-' + i + '" >'
      content += '<td class="urt-blacklist" id="urt-blacklist-' + i + '" style=" cursor: pointer; " title="' + (WMEURMPT.URList[i].blackListed ? 'whitelist' : 'blacklist') + ' this UR" >&nbsp;</td>'
      const colorCode = {}
      colorCode.fc = '#000000'
      if (WMEURMPT.URList[i].blackListed) {
        colorCode.bg = '#000000'
        colorCode.fc = '#ffffff'
      } else {
        if (WMEURMPT.URList[i].data.open === false) {
          colorCode.bg = '#00a000'
        } else {
          colorCode.bg = WMEURMPT.getColorFromAge(URDays)
        }
      }
      const HRURDays = '' + URDays
      let HRURLCDays = '-'
      if (lastCommentDays != null) {
        HRURLCDays = '' + lastCommentDays
      }
      const ttt = HRURDays + ' days'
      let closedBy = ''
      if (WMEURMPT.URList[i].data.open === false) {
        closedBy = ' - Closed as ' + WMEURMPT.getHRURResolutionFromType(WMEURMPT.URList[i].data.resolution) + ' by: ' + WMEURMPT.URList[i].data.resolvedByName
      }
      if (WMEURMPT.URAgeColIsLastComment) {
        content += '<td title="' + ttt + closedBy + '" style="text-align: center; background-color: ' + colorCode.bg + '; color: ' + colorCode.fc + ';"><span style="width: 100%; display: block;">' + HRURLCDays + '</span></td>'
      } else {
        content += '<td title="' + HRURLCDays + ' days' + closedBy + '" style="text-align: center; background-color: ' + colorCode.bg + '; color: ' + colorCode.fc + ';"><span style="width: 100%; display: block;">' + HRURDays + '</span></td>'
      }
      content += '<td>' + WMEURMPT.getHRURTypeFromType(WMEURMPT.URList[i].data.type) + '</td>'
      let descriptionHTML = ''
      if (WMEURMPT.URList[i].data.description != null) {
        descriptionHTML = WMEURMPT.escapeHtml(WMEURMPT.URList[i].data.description)
      }

      content += '<td style="max-width:' + WMEURMPT.URDescriptionMaxLength + 'ch; text-overflow: ellipsis; overflow: hidden; white-space: nowrap;"><span id="urt-descriptionur-' + WMEURMPT.URList[i].id + '" title="' + descriptionHTML + '">' + descriptionHTML + '</span></td>'
      content += '<td style="text-align: center"><span  id="urt-commentscount-' + i + '" style="width: 100%; display: block;" title="' + WMEURMPT.escapeHtml(comments) + '">' + WMEURMPT.URList[i].data.session.comments.length + '</span></td>'
      content += '<td style="text-align: right">' + distanceStr + '</td>'
      content += '<td style="width: 20px;" id="urt-targetur-' + i + '" title="' + WMEURMPT.URList[i].id + '"><a href="#"><center><i class="fa fa-crosshairs crosshair icon-screenshot"></i></center></a></td>'
      content += '</tr>'
    }
    content += '</table>'
    WMEURMPT.removeChildElements(div)
    div.innerHTML = WMEURMPT.convertHtml(displayedURCount + ' URs (' + hiddenURCount + ' hidden)<br/>' + content)
    let asort = WMEURMPT.getId('urt-table-sort-age')
    asort.onclick = (function () {
      let newSortMode = WMEURMPT.sortModeListUR.ageDSC
      if (WMEURMPT.currentSortModeUR === WMEURMPT.sortModeListUR.ageDSC || WMEURMPT.currentSortModeUR === WMEURMPT.sortModeListUR.ageASC) {
        newSortMode = WMEURMPT.currentSortModeUR * -1
      }
      return function () {
        WMEURMPT.changeTableURSortTo(newSortMode + '')
      }
    }())
    asort = WMEURMPT.getId('urt-table-sort-type')
    asort.onclick = (function () {
      let newSortMode = WMEURMPT.sortModeListUR.typeDSC
      if (WMEURMPT.currentSortModeUR === WMEURMPT.sortModeListUR.typeDSC || WMEURMPT.currentSortModeUR === WMEURMPT.sortModeListUR.typeASC) {
        newSortMode = WMEURMPT.currentSortModeUR * -1
      }
      return function () {
        WMEURMPT.changeTableURSortTo(newSortMode + '')
      }
    }())
    asort = WMEURMPT.getId('urt-table-sort-ccount')
    asort.onclick = (function () {
      let newSortMode = WMEURMPT.sortModeListUR.commentCountDSC
      if (WMEURMPT.currentSortModeUR === WMEURMPT.sortModeListUR.commentCountDSC || WMEURMPT.currentSortModeUR === WMEURMPT.sortModeListUR.commentCountASC) {
        newSortMode = WMEURMPT.currentSortModeUR * -1
      }
      return function () {
        WMEURMPT.changeTableURSortTo(newSortMode + '')
      }
    }())
    asort = WMEURMPT.getId('urt-table-sort-distance')
    asort.onclick = (function () {
      let newSortMode = WMEURMPT.sortModeListUR.distanceDSC
      if (WMEURMPT.currentSortModeUR === WMEURMPT.sortModeListUR.distanceDSC || WMEURMPT.currentSortModeUR === WMEURMPT.sortModeListUR.distanceASC) {
        newSortMode = WMEURMPT.currentSortModeUR * -1
      }
      return function () {
        WMEURMPT.changeTableURSortTo(newSortMode + '')
      }
    }())
    asort = WMEURMPT.getId('urt-table-sort-lastcomment')
    asort.onclick = (function () {
      let newSortMode = WMEURMPT.sortModeListUR.lastCommentDSC
      if (WMEURMPT.currentSortModeUR === WMEURMPT.sortModeListUR.lastCommentDSC || WMEURMPT.currentSortModeUR === WMEURMPT.sortModeListUR.lastCommentASC) {
        newSortMode = WMEURMPT.currentSortModeUR * -1
      }
      return function () {
        WMEURMPT.changeTableURSortTo(newSortMode + '')
      }
    }())
    window.setTimeout(WMEURMPT.setupURListHandlers)
    WMEURMPT.updateFlashingURs()
  }

  WMEURMPT.setupURListHandlers = function () {
    const table = WMEURMPT.getId('urmpt-ur-table')
    if (table == null) {
      return
    }
    if (table.childNodes.length !== 2) {
      return
    }
    const rows = table.childNodes[1].childNodes
    for (let i = 0; i < rows.length; i++) {
      const row = rows[i]
      const cellBlackList = row.childNodes[0]
      const cellTarget = row.childNodes[row.childNodes.length - 1]
      const indexInList = cellTarget.id.split('-')[2]
      cellBlackList.onclick = WMEURMPT.getFunctionWithArgs(WMEURMPT.blacklistUR, [indexInList])
      const lonlat = WMEURMPT.URList[parseInt(indexInList)].lonlat
      const URId = WMEURMPT.URList[parseInt(indexInList)].id
      cellTarget.onclick = WMEURMPT.getFunctionWithArgs(WMEURMPT.targetMapToUR, [lonlat.lon + '', lonlat.lat + '', URId + ''])
    }
  }

  WMEURMPT.updateIHMFromMPList = function (sortMode) {
    const div = WMEURMPT.getId('mpt-list')
    if (WMEURMPT.MPList.length === 0) {
      WMEURMPT.removeChildElements(div)
      div.innerHTML = WMEURMPT.convertHtml('')
      return
    }
    for (let i = 0; i < WMEURMPT.MPList.length; i++) {
      if (WMEURMPT.MPList[i].type === 'problem' && Object.prototype.hasOwnProperty.call(WMEURMPT.MPList[i].data, 'subType') && WMEURMPT.MPList[i].data.subType === 300) {
        const aDate = new Date()
        const now = aDate.getTime()
        const deltaH = (WMEURMPT.MPList[i].data.startTime - now) / 3600000
        let MPWeight = Math.ceil((720 - deltaH) / 7.2)
        if (deltaH > 0) {
          MPWeight = Math.ceil((720 - deltaH) / 14.4)
        }
        WMEURMPT.MPList[i].data.weight = MPWeight
      }
    }
    sortMode = typeof sortMode !== 'undefined' && sortMode != null ? sortMode : WMEURMPT.currentSortModeMP
    if (sortMode !== WMEURMPT.currentSortModeMP) {
      WMEURMPT.MPList.sort(WMEURMPT.compareMP)
      WMEURMPT.MPMap = WMEURMPT.listToObject(WMEURMPT.MPList)
    }
    WMEURMPT.currentSortModeMP = sortMode
    let content = ''
    content += '<table id="urmpt-mp-table" class="urt-table">'
    content += '<thead><tr>'
    content += '<td><div class="urt-table-head-icon"><img style="width: 16px" title="Blacklist UR 1 by 1." src="data:image/png;base64,' + WMEURMPT.icon_blacklist + '" /></div></td>'
    content += '<td><div class="urt-table-head-icon"><a href="#" id="mpt-table-sort-priority"><img style="width: 16px" title="Priority.' + NL + 'Click to sort." src="data:image/png;base64,' + WMEURMPT.icon_priority + '" /></a></div></td>'
    content += '<td style="max-width:' + WMEURMPT.MPDescriptionMaxLength + 'ch; text-overflow: ellipsis; overflow: hidden; white-space: nowrap;"><a href="#" id="mpt-table-sort-type" title="Type of the MP.' + NL + 'Click to sort.">Description</a></td>'
    content += '<td><div class="urt-table-head-icon"><a href="#" id="mpt-table-sort-distance"><img title="Distance to the center of the map.' + NL + 'Click to sort." src="data:image/png;base64,' + WMEURMPT.icon_distance + '" /></a></div></td>'
    content += '<td style="width: 20px; display: inline-block; border: none;"><center><div class="urt-table-head-icon"><i class="fa fa-crosshairs crosshair icon-screenshot"></i></div></center></td>'
    content += '</tr></thead>'
    let displayedMPCount = 0
    let hiddenMPCount = 0
    for (let i = 0; i < WMEURMPT.MPList.length; i++) {
      if (WMEURMPT.getId('mpt-checkbox-filterHideLimitTo').checked) {
        if (displayedMPCount >= WMEURMPT.currentMPLimitTo) {
          hiddenMPCount += WMEURMPT.MPList.length - i
          break
        }
      }
      if (WMEURMPT.isMPFiltered(WMEURMPT.MPList[i])) {
        hiddenMPCount++
        continue
      }
      displayedMPCount++
      let MPWeight = 0
      let isClosure = false
      if (WMEURMPT.MPList[i].type === 'problem' && Object.prototype.hasOwnProperty.call(WMEURMPT.MPList[i].data, 'subType') && WMEURMPT.MPList[i].data.subType === 300) {
        isClosure = true
      }
      if (WMEURMPT.MPList[i].type === 'problem') {
        MPWeight = WMEURMPT.MPList[i].data.priority
      }
      const distance = WMEURMPT.MPList[i].distanceToMapCenter
      let distanceStr = ''
      if (W.prefs.get('isImperial')) {
        distanceStr = Math.floor(distance * 3.28084) + '&nbsp;<font size: smaller>ft</font>'
        if (distance * 3.28084 >= 1000) {
          distanceStr = Math.floor(distance * 0.000621371) + '&nbsp;<font size: smaller>mi</font>'
        }
      } else {
        distanceStr = Math.floor(distance) + '&nbsp;<font size: smaller>m</font>'
        if (distance >= 1000) {
          distanceStr = Math.floor(distance / 1000) + '&nbsp;<font size: smaller>km</font>'
        }
        if (distance >= 1000000) {
          distanceStr = Math.floor(distance / 1000000) + '&nbsp;<font size: smaller>Mm</font>'
        }
      }
      content += '<tr id="mpt-tr-' + i + '" >'
      content += '<td class="urt-blacklist" id="mpt-blacklist-' + i + '" style="cursor: pointer;" title="' + (WMEURMPT.MPList[i].blackListed ? 'whitelist' : 'blacklist') + ' this MP" >&nbsp;</td>'
      const colorCode = {}
      colorCode.fc = '#000000'
      if (WMEURMPT.MPList[i].blackListed) {
        colorCode.bg = '#000000'
        colorCode.fc = '#ffffff'
      } else {
        if (WMEURMPT.MPList[i].data.open === false) {
          colorCode.bg = '#00a000'
        } else {
          colorCode.bg = WMEURMPT.getColorFromWieght(MPWeight)
        }
      }
      const HRMPWeight = '' + MPWeight
      const ttt = ''
      let closureDate = null
      if (isClosure) {
        let tmpDate = (new Date(WMEURMPT.MPList[i].data.startTime)).toLocaleString()
        tmpDate = tmpDate.split(' ')
        closureDate = tmpDate[0]
        closureDate = closureDate.replace(',', '')
        closureDate = closureDate.replace(/20([0-9][0-9])/, '$1')
      }
      content += '<td style="text-align: right; background-color: ' + colorCode.bg + '; color: ' + colorCode.fc + ';"><span ' + (WMEURMPT.MPList[i].data.open === true ? ttt !== '' ? 'title="' + ttt + '"' : '' : 'title="' + ttt + (ttt !== '' ? NL : '') + 'Closed as ' + WMEURMPT.getHRURResolutionFromType(WMEURMPT.MPList[i].data.resolution) + ' by: ' + WMEURMPT.MPList[i].data.resolvedByName + '" ') + ' style="width: 100%; display: block;">' + (isClosure ? closureDate : HRMPWeight) + '</span></td>'
      const descriptionHTML = WMEURMPT.MPList[i].type === 'turnProblem' ? 'Turn Problem' : WMEURMPT.getFullMPTypeFromType(WMEURMPT.MPList[i].data.subType)

      content += '<td style="max-width:' + WMEURMPT.MPDescriptionMaxLength + 'ch; text-overflow: ellipsis; overflow: hidden; white-space: nowrap;"><span id="mpt-descriptionmp-' + WMEURMPT.MPList[i].id + '" title="' + WMEURMPT.escapeHtml(descriptionHTML) + '">' + WMEURMPT.escapeHtml(descriptionHTML) + '</span></td>'
      content += '<td style="text-align: right">' + distanceStr + '</td>'
      content += '<td style="width: 20px;" id="mpt-targetmp-' + i + (WMEURMPT.isDebug ? '" title="' + WMEURMPT.MPList[i].id : '') + '"><a href="#"><center><i class="fa fa-crosshairs crosshair icon-screenshot"></i></center></a></td>'
      content += '</tr>'
    }
    content += '</table>'
    WMEURMPT.removeChildElements(div)
    div.innerHTML = WMEURMPT.convertHtml(displayedMPCount + ' MPs (' + hiddenMPCount + ' hidden)<br/>' + content)
    let asort = WMEURMPT.getId('mpt-table-sort-priority')
    asort.onclick = (function () {
      let newSortMode = WMEURMPT.sortModeListMP.priorityDSC
      if (WMEURMPT.currentSortModeMP === WMEURMPT.sortModeListMP.priorityDSC || WMEURMPT.currentSortModeMP === WMEURMPT.sortModeListMP.priorityASC) {
        newSortMode = WMEURMPT.currentSortModeMP * -1
      }
      return function () {
        WMEURMPT.changeTableMPSortTo(newSortMode + '')
      }
    }())
    asort = WMEURMPT.getId('mpt-table-sort-type')
    asort.onclick = (function () {
      let newSortMode = WMEURMPT.sortModeListMP.typeDSC
      if (WMEURMPT.currentSortModeMP === WMEURMPT.sortModeListMP.typeDSC || WMEURMPT.currentSortModeMP === WMEURMPT.sortModeListMP.typeASC) {
        newSortMode = WMEURMPT.currentSortModeMP * -1
      }
      return function () {
        WMEURMPT.changeTableMPSortTo(newSortMode + '')
      }
    }())
    asort = WMEURMPT.getId('mpt-table-sort-distance')
    asort.onclick = (function () {
      let newSortMode = WMEURMPT.sortModeListMP.distanceDSC
      if (WMEURMPT.currentSortModeMP === WMEURMPT.sortModeListMP.distanceDSC || WMEURMPT.currentSortModeMP === WMEURMPT.sortModeListMP.distanceASC) {
        newSortMode = WMEURMPT.currentSortModeMP * -1
      }
      return function () {
        WMEURMPT.changeTableMPSortTo(newSortMode + '')
      }
    }())
    window.setTimeout(WMEURMPT.setupMPListHandlers)
    WMEURMPT.updateFlashingMPs()
  }

  WMEURMPT.setupMPListHandlers = function () {
    const table = WMEURMPT.getId('urmpt-mp-table')
    if (table == null) {
      return
    }
    if (table.childNodes.length !== 2) {
      return
    }
    const rows = table.childNodes[1].childNodes
    for (let i = 0; i < rows.length; i++) {
      const row = rows[i]
      const cellBlackList = row.childNodes[0]
      const cellTarget = row.childNodes[row.childNodes.length - 1]
      const indexInList = cellTarget.id.split('-')[2]
      cellBlackList.onclick = WMEURMPT.getFunctionWithArgs(WMEURMPT.blacklistMP, [indexInList])
      const lonlat = WMEURMPT.MPList[parseInt(indexInList)].lonlat
      const MPId = WMEURMPT.MPList[parseInt(indexInList)].id
      cellTarget.onclick = WMEURMPT.getFunctionWithArgs(WMEURMPT.targetMapToMP, [lonlat.lon, lonlat.lat, MPId])
    }
  }

  WMEURMPT.updateIHMFromMCList = function (sortMode) {
    const div = WMEURMPT.getId('mct-list')
    if (WMEURMPT.MCList.length === 0) {
      WMEURMPT.removeChildElements(div)
      div.innerHTML = WMEURMPT.convertHtml('')
      return
    }
    sortMode = typeof sortMode !== 'undefined' && sortMode != null ? sortMode : WMEURMPT.currentSortModeMC
    if (sortMode !== WMEURMPT.currentSortModeMC) {
      WMEURMPT.MCList.sort(WMEURMPT.compareMC)
      WMEURMPT.MCMap = WMEURMPT.listToObject(WMEURMPT.MCList)
    }
    WMEURMPT.currentSortModeMC = sortMode
    let content = ''

    content += '<table id="urmpt-mc-table" class="urt-table">'
    content += '<thead><tr>'
    content += '<td><div class="urt-table-head-icon"><img style="width: 16px" title="Blacklist MC 1 by 1." src="data:image/png;base64,' + WMEURMPT.icon_blacklist + '" /></div></td>'
    content += '<td><div class="urt-table-head-icon"><a href="#" id="mct-table-sort-age"><img style="width: 16px" title="Age of the MC.' + NL + 'Click to sort." src="data:image/png;base64,' + WMEURMPT.icon_age + '" /></a></div></td>'
    content += '<td style="max-width:' + WMEURMPT.MCSubjectMaxLength + 'ch; text-overflow: ellipsis; overflow: hidden; white-space: nowrap;">Subject</td>'
    content += '<td style="max-width:' + WMEURMPT.MCBodyMaxLength + 'ch; text-overflow: ellipsis; overflow: hidden; white-space: nowrap;">Body</td>'
    content += '<td><div class="urt-table-head-icon"><a href="#" id="mct-table-sort-ccount"><img style="width: 16px" title="Comments count' + NL + 'Click to sort." src="data:image/png;base64,' + WMEURMPT.icon_comments + '" /></a></div></td>'
    content += '<td><div class="urt-table-head-icon"><a href="#" id="mct-table-sort-distance"><img title="Distance to the center of the map.' + NL + 'Click to sort." src="data:image/png;base64,' + WMEURMPT.icon_distance + '" /></a></div></td>'
    content += '<td style="width: 20px; display: inline-block; border: none;"><center><div class="urt-table-head-icon"><i class="fa fa-crosshairs crosshair icon-screenshot"></i></div></center></td>'
    content += '</tr></thead>'
    let displayedMCCount = 0
    let hiddenMCCount = 0
    for (let i = 0; i < WMEURMPT.MCList.length; i++) {
      if (WMEURMPT.getId('mct-checkbox-filterHideLimitTo').checked) {
        if (displayedMCCount >= WMEURMPT.currentMCLimitTo) {
          hiddenMCCount += WMEURMPT.MCList.length - i
          break
        }
      }
      if (WMEURMPT.isMCFiltered(WMEURMPT.MCList[i])) {
        hiddenMCCount++
        continue
      }
      displayedMCCount++
      let MCDays = 0
      if (WMEURMPT.MCList[i].data.createdOn !== null) {
        MCDays = WMEURMPT.getDuration(WMEURMPT.MCList[i].data.createdOn)
      }
      let conversation = ''
      if (Object.prototype.hasOwnProperty.call(WMEURMPT.MCList[i].data, 'conversation')) {
        const conversationArray = []
        WMEURMPT.MCList[i].data.conversation.forEach(function (c, j) {
          let text = c.userName + ' (' + (new Date(c.createdOn)).toLocaleString() + '):' + NL
          text += c.text
          conversationArray.push(text)
          if (j === WMEURMPT.MCList[i].data.conversation.length - 1 && c.userName === WMEURMPT.me.getUsername()) {
            WMEURMPT.MCList[i].lastVisitCommentsCount = WMEURMPT.MCList[i].data.conversation.length
          }
        })
        conversation = conversationArray.join(NL + NL)
      }
      const distance = WMEURMPT.MCList[i].distanceToMapCenter
      let distanceStr = ''
      if (W.prefs.get('isImperial')) {
        distanceStr = Math.floor(distance * 3.28084) + '&nbsp;<font size: smaller>ft</font>'
        if (distance * 3.28084 >= 1000) {
          distanceStr = Math.floor(distance * 0.000621371) + '&nbsp;<font size: smaller>mi</font>'
        }
      } else {
        distanceStr = Math.floor(distance) + '&nbsp;<font size: smaller>m</font>'
        if (distance >= 1000) {
          distanceStr = Math.floor(distance / 1000) + '&nbsp;<font size: smaller>km</font>'
        }
        if (distance >= 1000000) {
          distanceStr = Math.floor(distance / 1000000) + '&nbsp;<font size: smaller>Mm</font>'
        }
      }
      content += '<tr id="mct-tr-' + i + '" >'
      content += '<td class="urt-blacklist" id="mct-blacklist-' + i + '" style="cursor: pointer; ' + (WMEURMPT.MCList[i].blackListed ? 'background-color: #000; color: #FFF;' : 'background-color: #FFF; color: #000;') + '" title="' + (WMEURMPT.MCList[i].blackListed ? 'whitelist' : 'blacklist') + ' this MC" >&nbsp;</td>'
      content += '<td title="' + MCDays + ' days" style="text-align: center;"><span style="width: 100%; display: block;">' + MCDays + '</span></td>'
      let subjectHTML = ''
      if (typeof WMEURMPT.MCList[i].data.subject !== 'undefined') {
        subjectHTML = WMEURMPT.MCList[i].data.subject
      }

      content += '<td style="max-width:' + WMEURMPT.MCSubjectMaxLength + 'ch; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;"><span id="mct-subjectmc-' + WMEURMPT.MCList[i].id + '" title="' + WMEURMPT.escapeHtml(subjectHTML) + '">' + WMEURMPT.escapeHtml(subjectHTML) + '</span></td>'

      let bodyHTML = ''
      if (typeof WMEURMPT.MCList[i].data.body !== 'undefined') {
        bodyHTML = WMEURMPT.MCList[i].data.body
      }

      content += '<td style="max-width:' + WMEURMPT.MCBodyMaxLength + 'ch; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;"><span id="mct-bodymc-' + WMEURMPT.MCList[i].id + '" title="' + WMEURMPT.escapeHtml(bodyHTML) + '">' + WMEURMPT.escapeHtml(bodyHTML) + '</span></td>'
      content += '<td style="text-align: center"><span  id="mct-commentscount-' + i + '" style="width: 100%; display: block;" title="' + WMEURMPT.escapeHtml(conversation) + '">' + (Object.prototype.hasOwnProperty.call(WMEURMPT.MCList[i].data, 'conversation') ? WMEURMPT.MCList[i].data.conversation.length : '0') + '</span></td>'
      content += '<td style="text-align: right">' + distanceStr + '</td>'
      content += '<td style="width: 20px;" id="mct-targetmc-' + i + (WMEURMPT.isDebug ? '" title="' + WMEURMPT.MCList[i].id : '') + '"><a href="#"><center><i class="fa fa-crosshairs crosshair icon-screenshot"></i></center></a></td>'
      content += '</tr>'
    }
    content += '</table>'
    WMEURMPT.removeChildElements(div)
    div.innerHTML = WMEURMPT.convertHtml(displayedMCCount + ' MCs (' + hiddenMCCount + ' hidden)<br/>' + content)
    let asort = WMEURMPT.getId('mct-table-sort-age')
    asort.onclick = (function () {
      let newSortMode = WMEURMPT.sortModeListMC.ageDSC
      if (WMEURMPT.currentSortModeMC === WMEURMPT.sortModeListMC.ageDSC || WMEURMPT.currentSortModeMC === WMEURMPT.sortModeListMC.ageASC) {
        newSortMode = WMEURMPT.currentSortModeMC * -1
      }
      return function () {
        WMEURMPT.changeTableMCSortTo(newSortMode + '')
      }
    }())
    asort = WMEURMPT.getId('mct-table-sort-distance')
    asort.onclick = (function () {
      let newSortMode = WMEURMPT.sortModeListMC.distanceDSC
      if (WMEURMPT.currentSortModeMC === WMEURMPT.sortModeListMC.distanceDSC || WMEURMPT.currentSortModeMC === WMEURMPT.sortModeListMC.distanceASC) {
        newSortMode = WMEURMPT.currentSortModeMC * -1
      }
      return function () {
        WMEURMPT.changeTableMCSortTo(newSortMode + '')
      }
    }())
    asort = WMEURMPT.getId('mct-table-sort-ccount')
    asort.onclick = (function () {
      let newSortMode = WMEURMPT.sortModeListMC.commentCountDSC
      if (WMEURMPT.currentSortModeMC === WMEURMPT.sortModeListMC.commentCountDSC || WMEURMPT.currentSortModeMC === WMEURMPT.sortModeListMC.commentCountASC) {
        newSortMode = WMEURMPT.currentSortModeMC * -1
      }
      return function () {
        WMEURMPT.changeTableMCSortTo(newSortMode + '')
      }
    }())
    window.setTimeout(WMEURMPT.setupMCListHandlers)
    WMEURMPT.updateFlashingMCs()
  }
  WMEURMPT.setupMCListHandlers = function () {
    const table = WMEURMPT.getId('urmpt-mc-table')
    if (table == null) {
      return
    }
    if (table.childNodes.length !== 2) {
      return
    }
    const rows = table.childNodes[1].childNodes
    for (let i = 0; i < rows.length; i++) {
      const row = rows[i]
      const cellBlackList = row.childNodes[0]
      const cellTarget = row.childNodes[row.childNodes.length - 1]
      const indexInList = cellTarget.id.split('-')[2]
      cellBlackList.onclick = WMEURMPT.getFunctionWithArgs(WMEURMPT.blacklistMC, [indexInList])
      const lonlat = WMEURMPT.MCList[parseInt(indexInList)].lonlat
      const MCId = WMEURMPT.MCList[parseInt(indexInList)].id
      cellTarget.onclick = WMEURMPT.getFunctionWithArgs(WMEURMPT.targetMapToMC, [lonlat.lon, lonlat.lat, MCId])
    }
  }

  WMEURMPT.updateIHMFromPURList = function (sortMode) {
    const div = WMEURMPT.getId('purt-list')
    if (WMEURMPT.PURList.length === 0) {
      WMEURMPT.removeChildElements(div)
      div.innerHTML = WMEURMPT.convertHtml('')
      return
    }
    sortMode = typeof sortMode !== 'undefined' && sortMode !== null ? sortMode : WMEURMPT.currentSortModePUR
    if (sortMode !== WMEURMPT.currentSortModePUR) {
      WMEURMPT.PURList.sort(WMEURMPT.comparePUR)
      WMEURMPT.PURMap = WMEURMPT.listToObject(WMEURMPT.PURList)
    }
    WMEURMPT.currentSortModePUR = sortMode
    let content = ''
    content += '<table id="urmpt-pur-table" class="urt-table">'
    content += '<thead><tr>'
    content += '<td><div class="urt-table-head-icon"><img style="width: 16px" title="Blacklist PUR 1 by 1." src="data:image/png;base64,' + WMEURMPT.icon_blacklist + '" /></div></td>'
    content += '<td><div class="urt-table-head-icon"><a href="#" id="purt-table-sort-age"><img style="width: 16px" title="Age of the PUR.' + NL + 'Click to sort." src="data:image/png;base64,' + WMEURMPT.icon_age + '" /></a></div></td>'
    content += '<td><div class="urt-table-head-icon"><a href="#" id="purt-table-sort-nbpur"><img style="width: 16px" title="Number of PUR on the Poi.' + NL + 'Click to sort." src="data:image/png;base64,' + WMEURMPT.icon_pur + '" /></a></div></td>'
    content += '<td style="max-width:' + WMEURMPT.PURCategoriesMaxLength + 'ch; text-overflow: ellipsis; overflow: hidden; white-space: nowrap;"><a href="#" id="purt-table-sort-categories"  title="Categories of the POI.' + NL + 'Click to sort.">Categories</a></td>'
    content += '<td style="max-width:' + WMEURMPT.PURNameMaxLength + 'ch; text-overflow: ellipsis; overflow: hidden; white-space: nowrap;"><a href="#" id="purt-table-sort-name"  title="Name of the POI.' + NL + 'Click to sort.">Name</a></td>'
    content += '<td><div class="urt-table-head-icon"><a href="#" id="purt-table-sort-distance"><img title="Distance to the center of the map.' + NL + 'Click to sort." src="data:image/png;base64,' + WMEURMPT.icon_distance + '" /></a></div></td>'
    content += '<td style="width: 20px; display: inline-block; border: none;"><center><div class="urt-table-head-icon"><i class="fa fa-crosshairs crosshair icon-screenshot"></i></div></center></td>'
    content += '</tr></thead>'
    let displayedPURCount = 0
    let hiddenPURCount = 0
    for (let i = 0; i < WMEURMPT.PURList.length; i++) {
      if (WMEURMPT.getId('purt-checkbox-filterHideLimitTo').checked) {
        if (displayedPURCount >= WMEURMPT.currentPURLimitTo) {
          hiddenPURCount += WMEURMPT.PURList.length - i
          break
        }
      }
      if (WMEURMPT.isPURFiltered(WMEURMPT.PURList[i])) {
        hiddenPURCount++
        continue
      }
      if (Object.prototype.hasOwnProperty.call(WMEURMPT.PURList[i].data, 'venueUpdateRequests') && WMEURMPT.PURList[i].data.venueUpdateRequests.length === 0) {
        continue
      }
      displayedPURCount++
      const PURDays = WMEURMPT.getDuration(WMEURMPT.PURList[i].data.dateAddedMin)
      let nbPUR = null
      if (Object.prototype.hasOwnProperty.call(WMEURMPT.PURList[i].data, 'venueUpdateRequests') && WMEURMPT.PURList[i].data.venueUpdateRequests.length !== 0) {
        nbPUR = WMEURMPT.PURList[i].data.venueUpdateRequests.length
      }
      const distance = WMEURMPT.PURList[i].distanceToMapCenter
      let distanceStr = ''
      if (W.prefs.get('isImperial')) {
        distanceStr = Math.floor(distance * 3.28084) + '&nbsp;<font size: smaller>ft</font>'
        if (distance * 3.28084 >= 1000) {
          distanceStr = Math.floor(distance * 0.000621371) + '&nbsp;<font size: smaller>mi</font>'
        }
      } else {
        distanceStr = Math.floor(distance) + '&nbsp;<font size: smaller>m</font>'
        if (distance >= 1000) {
          distanceStr = Math.floor(distance / 1000) + '&nbsp;<font size: smaller>km</font>'
        }
        if (distance >= 1000000) {
          distanceStr = Math.floor(distance / 1000000) + '&nbsp;<font size: smaller>Mm</font>'
        }
      }
      content += '<tr id="purt-tr-' + i + '" >'
      content += '<td class="urt-blacklist" id="purt-blacklist-' + i + '" style="cursor: pointer;" title="' + (WMEURMPT.PURList[i].blackListed ? 'whitelist' : 'blacklist') + ' this PUR" >&nbsp;</td>'
      content += '<td title="' + PURDays + ' days" style="text-align: center;"><span style="width: 100%; display: block;">' + PURDays + '</span></td>'
      content += '<td title="' + nbPUR + ' pur(s)" style="text-align: center;"><span style="width: 100%; display: block;">' + nbPUR + '</span></td>'
      let categoriesHTML = ''
      for (let n = 0; n < WMEURMPT.PURList[i].data.categories.length; n++) {
        categoriesHTML += WMEURMPT.getPURCategoriesFromCategories(WMEURMPT.PURList[i].data.categories[n]) + ' '
      }

      content += '<td style="max-width: ' + WMEURMPT.PURCategoriesMaxLength + 'ch; text-overflow: ellipsis; overflow: hidden; white-space: nowrap;"><span id="purt-categoriespur-' + WMEURMPT.PURList[i].id + '" title="' + WMEURMPT.escapeHtml(categoriesHTML) + '">' + WMEURMPT.escapeHtml(categoriesHTML) + '</span></td>'
      let nameHTML = WMEURMPT.PURList[i].data.name
      if (typeof nameHTML === 'undefined') {
        nameHTML = 'undefined'
      }

      content += '<td style="max-width:' + WMEURMPT.PURNameMaxLength + 'ch; text-overflow: ellipsis; overflow: hidden; white-space: nowrap;"><span id="purt-namepur-' + WMEURMPT.PURList[i].id + '" title="' + WMEURMPT.escapeHtml(nameHTML) + '">' + WMEURMPT.escapeHtml(nameHTML) + '</span></td>'
      content += '<td style="text-align: right">' + distanceStr + '</td>'
      content += '<td style="width: 20px;" id="purt-targetpur-' + i + (WMEURMPT.isDebug ? '" title="' + WMEURMPT.PURList[i].id : '') + '"><a href="#"><center><i class="fa fa-crosshairs crosshair icon-screenshot"></i></center></a></td>'
      content += '</tr>'
    }
    content += '</table>'
    WMEURMPT.removeChildElements(div)
    div.innerHTML = WMEURMPT.convertHtml(displayedPURCount + ' PURs (' + hiddenPURCount + ' hidden)<br/>' + content)
    let asort = WMEURMPT.getId('purt-table-sort-age')
    asort.onclick = (function () {
      let newSortMode = WMEURMPT.sortModeListPUR.ageDSC
      if (WMEURMPT.currentSortModePUR === WMEURMPT.sortModeListPUR.ageDSC || WMEURMPT.currentSortModePUR === WMEURMPT.sortModeListPUR.ageASC) {
        newSortMode = WMEURMPT.currentSortModePUR * -1
      }
      return function () {
        WMEURMPT.changeTablePURSortTo(newSortMode + '')
      }
    }())
    asort = WMEURMPT.getId('purt-table-sort-categories')
    asort.onclick = (function () {
      let newSortMode = WMEURMPT.sortModeListPUR.categoriesDSC
      if (WMEURMPT.currentSortModePUR === WMEURMPT.sortModeListPUR.categoriesDSC || WMEURMPT.currentSortModePUR === WMEURMPT.sortModeListPUR.categoriesASC) {
        newSortMode = WMEURMPT.currentSortModePUR * -1
      }
      return function () {
        WMEURMPT.changeTablePURSortTo(newSortMode + '')
      }
    }())
    asort = WMEURMPT.getId('purt-table-sort-name')
    asort.onclick = (function () {
      let newSortMode = WMEURMPT.sortModeListPUR.nameDSC
      if (WMEURMPT.currentSortModePUR === WMEURMPT.sortModeListPUR.nameDSC || WMEURMPT.currentSortModePUR === WMEURMPT.sortModeListPUR.nameASC) {
        newSortMode = WMEURMPT.currentSortModePUR * -1
      }
      return function () {
        WMEURMPT.changeTablePURSortTo(newSortMode + '')
      }
    }())
    asort = WMEURMPT.getId('purt-table-sort-distance')
    asort.onclick = (function () {
      let newSortMode = WMEURMPT.sortModeListPUR.distanceDSC
      if (WMEURMPT.currentSortModePUR === WMEURMPT.sortModeListPUR.distanceDSC || WMEURMPT.currentSortModePUR === WMEURMPT.sortModeListPUR.distanceASC) {
        newSortMode = WMEURMPT.currentSortModePUR * -1
      }
      return function () {
        WMEURMPT.changeTablePURSortTo(newSortMode + '')
      }
    }())
    asort = WMEURMPT.getId('purt-table-sort-nbpur')
    asort.onclick = (function () {
      let newSortMode = WMEURMPT.sortModeListPUR.nbpurDSC
      if (WMEURMPT.currentSortModePUR === WMEURMPT.sortModeListPUR.nbpurDSC || WMEURMPT.currentSortModePUR === WMEURMPT.sortModeListPUR.nbpurASC) {
        newSortMode = WMEURMPT.currentSortModePUR * -1
      }
      return function () {
        WMEURMPT.changeTablePURSortTo(newSortMode + '')
      }
    }())
    window.setTimeout(WMEURMPT.setupPURListHandlers)
    WMEURMPT.updateFlashingPURs()
  }

  WMEURMPT.setupPURListHandlers = function () {
    const table = WMEURMPT.getId('urmpt-pur-table')
    if (table == null) {
      return
    }
    if (table.childNodes.length !== 2) {
      return
    }
    const rows = table.childNodes[1].childNodes
    for (let i = 0; i < rows.length; i++) {
      const row = rows[i]
      const cellBlackList = row.childNodes[0]
      const cellTarget = row.childNodes[row.childNodes.length - 1]
      const indexInList = cellTarget.id.split('-')[2]
      cellBlackList.onclick = WMEURMPT.getFunctionWithArgs(WMEURMPT.blacklistPUR, [indexInList])
      const lonlat = WMEURMPT.PURList[parseInt(indexInList)].lonlat
      const PURId = WMEURMPT.PURList[parseInt(indexInList)].id
      cellTarget.onclick = WMEURMPT.getFunctionWithArgs(WMEURMPT.targetMapToPUR, [lonlat.lon, lonlat.lat, PURId])
    }
  }

  WMEURMPT.updateFlashingURs = function () {
    for (let i = 0; i < WMEURMPT.URList.length; i++) {
      const urObj = WMEURMPT.URList[i]
      if (WMEURMPT.isURFiltered(urObj)) {
        continue
      }
      const span = WMEURMPT.getId('urt-commentscount-' + i)
      const tr = WMEURMPT.getId('urt-tr-' + i)
      if (span == null) {
        continue
      }
      if (tr == null) {
        continue
      }
      if (urObj.alreadyVisited === false && tr.className !== 'urt-bg-highlighted') {
        tr.className = 'urt-bg-highlighted'
      } else {
        if (urObj.alreadyVisited === true) {
          tr.className = ''
        }
      }
      if (urObj.data.session.isFollowing === true) {
        tr.className = 'urt-bg-ifollow'
      }
      if (urObj.id === WMEURMPT.selectedURID) {
        tr.className = 'urt-bg-selected'
      }
      if (Object.prototype.hasOwnProperty.call(urObj.data, 'session') === true && urObj.lastVisitCommentsCount < urObj.data.session.comments.length) {
        span.className = 'urt-bg-newcomments'
      } else {
        span.className = ''
      }
    }
    WMEURMPT.flashOdd = !WMEURMPT.flashOdd
  }

  WMEURMPT.updateFlashingMPs = function () {
    for (let i = 0; i < WMEURMPT.MPList.length; i++) {
      const tr = WMEURMPT.getId('mpt-tr-' + i)
      if (tr == null) {
        continue
      }
      if (WMEURMPT.MPList[i].alreadyVisited === false && tr.className !== 'urt-bg-highlighted') {
        tr.className = 'urt-bg-highlighted'
      } else {
        if (WMEURMPT.MPList[i].alreadyVisited === true) {
          tr.className = ''
        }
      }
      if (WMEURMPT.MPList[i].id === WMEURMPT.selectedMPID) {
        tr.className = 'urt-bg-selected'
      }
    }
  }

  WMEURMPT.updateFlashingMCs = function () {
    for (let i = 0; i < WMEURMPT.MCList.length; i++) {
      const tr = WMEURMPT.getId('mct-tr-' + i)
      if (tr == null) {
        continue
      }
      if (WMEURMPT.MCList[i].alreadyVisited === false && tr.className !== 'urt-bg-highlighted') {
        tr.className = 'urt-bg-highlighted'
      } else {
        if (WMEURMPT.MCList[i].alreadyVisited === true) {
          tr.className = ''
        }
      }
      if (WMEURMPT.MCList[i].id === WMEURMPT.selectedMCID) {
        tr.className = 'urt-bg-selected'
      }
      if (Object.prototype.hasOwnProperty.call(WMEURMPT.MCList[i].data, 'conversation') === true && WMEURMPT.MCList[i].lastVisitCommentsCount < WMEURMPT.MCList[i].data.conversation.length) {
        const span = WMEURMPT.getId('mct-commentscount-' + i)
        if (span != null) {
          span.className = 'urt-bg-newcomments'
        }
      }
    }
  }

  WMEURMPT.updateFlashingPURs = function () {
    for (let i = 0; i < WMEURMPT.PURList.length; i++) {
      const tr = WMEURMPT.getId('purt-tr-' + i)
      if (tr == null) {
        continue
      }
      if (WMEURMPT.PURList[i].alreadyVisited === false && tr.className !== 'urt-bg-highlighted') {
        tr.className = 'urt-bg-highlighted'
      } else {
        if (WMEURMPT.PURList[i].alreadyVisited === true) {
          tr.className = ''
        }
      }
      if (WMEURMPT.PURList[i].id === WMEURMPT.selectedPURID) {
        tr.className = 'urt-bg-selected'
      }
    }
  }
  WMEURMPT.updateLongTextCrop = function () {
    const urTable = WMEURMPT.getId('urmpt-ur-table')
    const mpTable = WMEURMPT.getId('urmpt-mp-table')
    const mcTable = WMEURMPT.getId('urmpt-mc-table')
    const purTable = WMEURMPT.getId('urmpt-pur-table')
    if (urTable) {
      if (urTable.children.length >= 2) {
        const lines = urTable.children[1].children
        let spanText = null
        for (let i = 0; i < lines.length; i++) {
          spanText = lines[i].children[3].firstChild
          if (spanText == null) {
            continue
          }
          if (typeof spanText === 'undefined') {
            continue
          }
          const urIndices = lines[i].id.match(/urt-tr-([0-9]+)/)
          if (urIndices.length !== 2) {
            continue
          }
          const urIndex = parseInt(urIndices[1])
          if (WMEURMPT.URList[urIndex].data.description == null) {
            continue
          }
          if (WMEURMPT.URList[urIndex].data.description.length <= WMEURMPT.URDescriptionMaxLength) {
            continue
          }
          if (typeof WMEURMPT.URList[urIndex].data.descriptionOffset === 'undefined') {
            WMEURMPT.URList[urIndex].data.descriptionOffset = -10
          }
          let pos = WMEURMPT.URList[urIndex].data.descriptionOffset
          if (WMEURMPT.URList[urIndex].data.descriptionOffset < 0) {
            pos = 0
          }
          const remaining = WMEURMPT.URList[urIndex].data.description.length - pos
          if (remaining < 10) {
            spanText.innerHTML = WMEURMPT.escapeHtml(WMEURMPT.URList[urIndex].data.description.substr(0, WMEURMPT.URDescriptionMaxLength))
            WMEURMPT.URList[urIndex].data.descriptionOffset = -10
          } else if (remaining < WMEURMPT.URDescriptionMaxLength) {
            WMEURMPT.URList[urIndex].data.descriptionOffset++
          } else {
            if (WMEURMPT.URList[urIndex].data.descriptionOffset > 0) {
              spanText.innerHTML = WMEURMPT.escapeHtml(WMEURMPT.URList[urIndex].data.description.substr(WMEURMPT.URList[urIndex].data.descriptionOffset + 1, WMEURMPT.URDescriptionMaxLength))
            }
            WMEURMPT.URList[urIndex].data.descriptionOffset++
          }
        }
      }
    }
    if (mpTable) {
      if (mpTable.children.length >= 2) {
        const lines = mpTable.children[1].children
        let spanText = null
        for (let i = 0; i < lines.length; i++) {
          spanText = lines[i].children[2].firstChild
          if (spanText == null) {
            continue
          }
          if (typeof spanText === 'undefined') {
            continue
          }
          const mpIndices = lines[i].id.match(/mpt-tr-([0-9]+)/)
          if (mpIndices.length !== 2) {
            continue
          }
          const mpIndex = parseInt(mpIndices[1])
          const description = WMEURMPT.MPList[mpIndex].type === 'turnProblem' ? 'Turn Problem' : WMEURMPT.getFullMPTypeFromType(WMEURMPT.MPList[mpIndex].data.subType)
          if (description == null) {
            continue
          }
          if (description.length <= WMEURMPT.MPDescriptionMaxLength) {
            continue
          }
          if (typeof WMEURMPT.MPList[mpIndex].data.descriptionOffset === 'undefined') {
            WMEURMPT.MPList[mpIndex].data.descriptionOffset = -10
          }
          let pos = WMEURMPT.MPList[mpIndex].data.descriptionOffset
          if (WMEURMPT.MPList[mpIndex].data.descriptionOffset < 0) {
            pos = 0
          }
          const remaining = description.length - pos
          if (remaining < 10) {
            spanText.innerHTML = WMEURMPT.escapeHtml(description.substr(0, WMEURMPT.MPDescriptionMaxLength))
            WMEURMPT.MPList[mpIndex].data.descriptionOffset = -10
          } else if (remaining < WMEURMPT.MPDescriptionMaxLength) {
            WMEURMPT.MPList[mpIndex].data.descriptionOffset++
          } else {
            if (WMEURMPT.MPList[mpIndex].data.descriptionOffset > 0) {
              spanText.innerHTML = WMEURMPT.escapeHtml(description.substr(WMEURMPT.MPList[mpIndex].data.descriptionOffset + 1, WMEURMPT.MPDescriptionMaxLength))
            }
            WMEURMPT.MPList[mpIndex].data.descriptionOffset++
          }
        }
      }
    }
    if (mcTable) {
      if (mcTable.children.length >= 2) {
        const lines = mcTable.children[1].children
        let spanText = null
        for (let i = 0; i < lines.length; i++) {
          [{ index: 2, att: 'subject', maxl: WMEURMPT.MCSubjectMaxLength }, { index: 3, att: 'body', maxl: WMEURMPT.MCBodyMaxLength }].forEach(function (child) {
            spanText = lines[i].children[child.index].firstChild
            if (spanText == null) {
              return
            }
            if (typeof spanText === 'undefined') {
              return
            }
            const mcIndices = lines[i].id.match(/mct-tr-([0-9]+)/)
            if (mcIndices.length !== 2) {
              return
            }
            const mcIndex = parseInt(mcIndices[1])
            const theMC = WMEURMPT.MCList[mcIndex]
            if (theMC.data[child.att] == null) {
              return
            }
            if (theMC.data[child.att].length <= child.maxl) {
              return
            }
            if (typeof theMC.data[child.att + 'Offset'] === 'undefined') {
              theMC.data[child.att + 'Offset'] = -10
            }
            let pos = theMC.data[child.att + 'Offset']
            if (theMC.data[child.att + 'Offset'] < 0) {
              pos = 0
            }
            const text = theMC.data[child.att]
            const remaining = theMC.data[child.att].length - pos
            if (remaining < 10) {
              spanText.innerHTML = WMEURMPT.escapeHtml(text.substr(0, child.maxl))
              theMC.data[child.att + 'Offset'] = -10
            } else if (remaining < child.maxl) {
              theMC.data[child.att + 'Offset']++
            } else {
              if (theMC.data[child.att + 'Offset'] > 0) {
                spanText.innerHTML = WMEURMPT.escapeHtml(text.substr(theMC.data[child.att + 'Offset'] + 1, child.maxl))
              }
              theMC.data[child.att + 'Offset']++
            }
          })
        }
      }
    }
    if (purTable) {
      if (purTable.children.length >= 2) {
        const lines = purTable.children[1].children
        let spanText = null
        for (let i = 0; i < lines.length; i++) {
          [{ index: 3, att: 'categories', maxl: WMEURMPT.PURCategoriesMaxLength }, { index: 4, att: 'name', maxl: WMEURMPT.PURNameMaxLength }].forEach(function (child) {
            spanText = lines[i].children[child.index].firstChild
            if (spanText == null) {
              return
            }
            if (typeof spanText === 'undefined') {
              return
            }
            const purIndices = lines[i].id.match(/purt-tr-([0-9]+)/)
            if (purIndices.length !== 2) {
              return
            }
            const purIndex = parseInt(purIndices[1])
            const thePUR = WMEURMPT.PURList[purIndex]
            if (thePUR.data[child.att] == null) {
              return
            }
            if (child.att === 'categories') {
              let categories = ''
              for (let n = 0; n < WMEURMPT.PURList[purIndex].data.categories.length; n++) {
                categories += WMEURMPT.getPURCategoriesFromCategories(WMEURMPT.PURList[purIndex].data.categories[n]) + ' '
              }
              if (categories.length <= child.maxl) {
                return
              }
              if (typeof thePUR.data.categoriesOffset === 'undefined') {
                thePUR.data.categoriesOffset = -10
              }
              let pos = thePUR.data.categoriesOffset
              if (thePUR.data.categoriesOffset < 0) {
                pos = 0
              }
              const text = categories
              const remaining = categories.length - pos
              if (remaining < 10) {
                spanText.innerHTML = WMEURMPT.escapeHtml(text.substr(0, child.maxl))
                thePUR.data.categoriesOffset = -10
              } else if (remaining < child.maxl) {
                thePUR.data.categoriesOffset++
              } else {
                if (thePUR.data.categoriesOffset > 0) {
                  spanText.innerHTML = WMEURMPT.escapeHtml(text.substr(thePUR.data.categoriesOffset + 1, child.maxl))
                }
                thePUR.data.categoriesOffset++
              }
            }
            if (child.att === 'name') {
              if (thePUR.data[child.att].length <= child.maxl) {
                return
              }
              if (typeof thePUR.data[child.att + 'Offset'] === 'undefined') {
                thePUR.data[child.att + 'Offset'] = -10
              }
              let pos = thePUR.data[child.att + 'Offset']
              if (thePUR.data[child.att + 'Offset'] < 0) {
                pos = 0
              }
              const text = thePUR.data[child.att]
              const remaining = thePUR.data[child.att].length - pos
              if (remaining < 10) {
                spanText.innerHTML = WMEURMPT.escapeHtml(text.substr(0, child.maxl))
                thePUR.data[child.att + 'Offset'] = -10
              } else if (remaining < child.maxl) {
                thePUR.data[child.att + 'Offset']++
              } else {
                if (thePUR.data[child.att + 'Offset'] > 0) {
                  spanText.innerHTML = WMEURMPT.escapeHtml(text.substr(thePUR.data[child.att + 'Offset'] + 1, child.maxl))
                }
                thePUR.data[child.att + 'Offset']++
              }
            }
          })
        }
      }
    }
    if (WMEURMPT.disableScrolling === false) {
      window.setTimeout(WMEURMPT.updateLongTextCrop, 150)
    }
  }

  WMEURMPT.targetMapToUR = function (lon, lat, URId) {
    WMEURMPT.log('Target map to UR: ' + URId)
    WMEURMPT.selectedURID = URId
    WMEURMPT.updateFlashingURs()
    const xy = OpenLayers.Layer.SphericalMercator.forwardMercator(parseFloat(lon), parseFloat(lat))
    WMEURMPT.wazeMap.setCenter(xy)
    URId = parseInt(URId)
    WMEURMPT.wazeMap.getLayerByName('update_requests').setVisibility(true)
    window.setTimeout(WMEURMPT.getFunctionWithArgs(WMEURMPT.selectURById, [{ URId, attempts: 0 }]), 250)
  }

  WMEURMPT.targetMapToMP = function (lon, lat, MPId) {
    WMEURMPT.log('Target map to MP: ' + MPId)
    WMEURMPT.selectedMPID = MPId
    WMEURMPT.updateFlashingMPs()
    const xy = OpenLayers.Layer.SphericalMercator.forwardMercator(lon, lat)
    WMEURMPT.wazeMap.setCenter(xy)
    WMEURMPT.wazeMap.getLayerByName('mapProblems').setVisibility(true)
    window.setTimeout(WMEURMPT.getFunctionWithArgs(WMEURMPT.selectMPById, [{ MPId, attempts: 0 }]), 250)
  }

  WMEURMPT.targetMapToMC = function (lon, lat, MCId) {
    WMEURMPT.log('Target map to MC: ' + MCId)
    WMEURMPT.selectedMCID = MCId
    WMEURMPT.updateFlashingMCs()
    const xy = OpenLayers.Layer.SphericalMercator.forwardMercator(lon, lat)
    WMEURMPT.wazeMap.setCenter(xy)
    WMEURMPT.wazeMap.getLayerByUniqueName('mapComments').setVisibility(true)
    window.setTimeout(WMEURMPT.getFunctionWithArgs(WMEURMPT.selectMCById, [{ MCId, attempts: 0 }]), 250)
  }

  WMEURMPT.targetMapToPUR = function (lon, lat, PURId) {
    WMEURMPT.log('Target map to PUR: ' + PURId)
    WMEURMPT.selectedPURID = PURId
    WMEURMPT.updateFlashingPURs()
    const xy = OpenLayers.Layer.SphericalMercator.forwardMercator(lon, lat)
    WMEURMPT.wazeMap.setCenter(xy)
    WMEURMPT.wazeMap.getLayerByUniqueName('place_updates').setVisibility(true)
    WMEURMPT.wazeMap.getLayerByUniqueName('venues').setVisibility(true)
    WMEURMPT.wazeMap.getLayerByUniqueName('PARKING_PLACE_UPDATES').setVisibility(true)
    WMEURMPT.wazeMap.getLayerByUniqueName('RESIDENTIAL_PLACE_UPDATES').setVisibility(true)
    window.setTimeout(WMEURMPT.getFunctionWithArgs(WMEURMPT.selectPURById, [{ PURId, attempts: 0 }]), 250)
  }

  WMEURMPT.selectURById = function (URId) {
    if (URId.attempts > 10) {
      WMEURMPT.log("Can't select UR " + URId.URId)
      return
    }
    if (URId.attempts === 0) {
      URId.didShow = false
    }
    WMEURMPT.wazeModel.updateRequestSessions.getAsync([URId.URId])
    const session = WMEURMPT.wazeModel.updateRequestSessions.objects[URId.URId]
    const ur = WMEURMPT.wazeModel.mapUpdateRequests.getObjectById(URId.URId)
    if (ur != null && session != null) {
      if (!URId.didShow) {
        WMEURMPT.logDebug('Select UR by ID: ' + URId.URId)
        WMEURMPT.wazePC.showProblem(ur, { showNext: false })
        URId.didShow = true
      }

      const selectedUR = WMEURMPT.wazeMap.getLayerByName('update_requests').features.filter(elem => (typeof elem.attributes.cluster === 'undefined') && (typeof elem.attributes.wazeFeature !== 'undefined') && (elem.attributes.wazeFeature.id === URId.URId))[0]
      if (selectedUR.attributes.wazeFeature.isSelected === false) {
        URId.attempts++
        WMEURMPT.log('Can not select UR ' + URId.URId + '. Trying again ' + URId.attempts + '/10...')
        window.setTimeout(WMEURMPT.getFunctionWithArgs(WMEURMPT.selectURById, [URId]), 100)
        return
      }
      if (!WMEURMPT.isAutoScan) {
        WMEURMPT.URJustOpened(URId.URId)
        // const theUR = WMEURMPT.getURFromId(URId.URId)
        // theUR.refreshFromWMEData(true)
        // WMEURMPT.updateIHMFromURList()
      }
      WMEURMPT.newDataAvailableStarts()

      return
    }
    URId.attempts++
    WMEURMPT.log('Can not select UR ' + URId.URId + '. Trying again ' + URId.attempts + '/10...')
    window.setTimeout(WMEURMPT.getFunctionWithArgs(WMEURMPT.selectURById, [URId]), 100)
  }

  WMEURMPT.selectMPById = function (MPId) {
    if (MPId.attempts > 10) {
      WMEURMPT.log("Can't select MP " + MPId.MPId)
      return
    }
    const mp = WMEURMPT.wazeModel.mapProblems.getObjectById(MPId.MPId)
    WMEURMPT.logDebug('mp :', mp)
    if (mp !== 'undefined') {
      WMEURMPT.wazePC.showProblem(mp, { showNext: false })

      const selectedMP = WMEURMPT.wazeMap.getLayerByName('mapProblems').features.filter(elem => elem.attributes.wazeFeature.id === MPId.MPId)[0]
      if (selectedMP.attributes.wazeFeature.isSelected === true) {
        WMEURMPT.MPVisited(MPId.MPId)
        WMEURMPT.currentMPID = MPId.MPId
        WMEURMPT.newDataAvailableStarts()
        return
      }
    }
    MPId.attempts++
    WMEURMPT.log('Can not select MP ' + MPId.MPId + '. Trying again ' + MPId.attempts + '/10...')
    window.setTimeout(WMEURMPT.getFunctionWithArgs(WMEURMPT.selectMPById, [MPId]), 100)
  }

  WMEURMPT.selectMCById = function (MCId) {
    if (MCId.attempts > 10) {
      WMEURMPT.log("Can't select MC " + MCId.MCId)
      return
    }
    const mc = WMEURMPT.wazeModel.mapComments.getObjectById(MCId.MCId)
    WMEURMPT.logDebug('mc :', mc)
    if (mc != null) {
      WMEURMPT.MCVisited(MCId.MCId)
      WMEURMPT.currentMCID = MCId.MCId
      WMEURMPT.newDataAvailableStarts()
      W.selectionManager.setSelectedModels([WMEURMPT.wazeModel.mapComments.getObjectById(MCId.MCId)])
      return
    }
    MCId.attempts++
    WMEURMPT.log('Can not select MC ' + MCId.MCId + '. Trying again ' + MCId.attempts + '/10...')
    window.setTimeout(WMEURMPT.getFunctionWithArgs(WMEURMPT.selectMCById, [MCId]), 100)
  }

  WMEURMPT.selectPURById = function (PURId) {
    if (PURId.attempts > 10) {
      WMEURMPT.log("Can't select PUR " + PURId.PURId)
      return
    }
    const pur = WMEURMPT.wazeModel.venues.getObjectById(PURId.PURId)
    WMEURMPT.logDebug('pur :', pur)
    if (pur != null) {
      WMEURMPT.PURVisited(PURId.PURId)
      WMEURMPT.currentPURID = PURId.PURId
      WMEURMPT.newDataAvailableStarts()
      W.selectionManager.setSelectedModels([WMEURMPT.wazeModel.venues.getObjectById(PURId.PURId)])
      return
    }
    PURId.attempts++
    WMEURMPT.log('Can not select PUR ' + PURId.PURId + '. Trying again ' + PURId.attempts + '/10...')
    window.setTimeout(WMEURMPT.getFunctionWithArgs(WMEURMPT.selectPURById, [PURId]), 100)
  }

  WMEURMPT.newDataAvailableStarts = function () {
    if (WMEURMPT.isScanningWME) {
      return
    }
    if (!WMEURMPT.isAutoScan) {
      // this.name = type of object being changed
      // this.objectType = type of object being changed
      // this.trigger.arguments (0 = event type, 1 = objects changed)

      switch (this.objectType) {
        case 'venue': {
          const purID = WMEURMPT.getSelectedPUR()
          WMEURMPT.log('scan only selected: PUR: ' + purID)
          if (purID != null) {
            const thePUR = WMEURMPT.getPURFromId(purID)
            if (thePUR != null) {
              thePUR.refreshFromWMEData()
            }
          }
          break
        }
        case 'mapComment': {
          const mcID = WMEURMPT.getSelectedMC()
          WMEURMPT.log('scan only selected: MC: ' + mcID)
          if (mcID != null && typeof mcID === 'number' && mcID > 0) {
            let theMC = WMEURMPT.getMCFromId(mcID)
            if (theMC != null) {
              theMC.refreshFromWMEData()
              WMEURMPT.updateIHMFromMCList()
            } else {
              theMC = WMEURMPT.getNewMC(mcID)
            }
          }
          break
        }
        case 'mapProblems': {
          const mpID = WMEURMPT.getSelectedProblem()
          WMEURMPT.log('scan only selected: MP: ' + mpID)
          if (mpID != null) {
            const theMP = WMEURMPT.getMPFromId(mpID)
            if (theMP != null) {
              theMP.refreshFromWMEData()
              WMEURMPT.updateIHMFromMPList()
            }
          }
          break
        }
        case 'mapUpdateRequets': {
          const urID = WMEURMPT.getSelectedUR()
          WMEURMPT.log('scan only selected: UR: ' + urID)
          if (urID != null) {
            const theUR = WMEURMPT.getURFromId(urID)
            if (theUR != null) {
              theUR.refreshFromWMEData(true)
              WMEURMPT.updateIHMFromURList()
            }
          }
        }
      }

      return
    }
    WMEURMPT.isScanningWME = true
    WMEURMPT.newDataAvailable(0)
  }

  WMEURMPT.newDataAvailable = function (i) {
    const pb = new WMEURMPT.ProgressBar(WMEURMPT.getId('urt-progressBar'))
    try {
      const URs = WMEURMPT.wazeModel.mapUpdateRequests.getObjectArray()
      const MPs = WMEURMPT.wazeModel.mapProblems.getObjectArray()
      const MCs = WMEURMPT.wazeModel.mapComments.getObjectArray()
      const POIs = WMEURMPT.wazeModel.venues.getObjectArray()
      const PURs = []
      for (let n = 0; n < POIs.length; n++) {
        if (Object.prototype.hasOwnProperty.call(POIs[n].attributes, 'venueUpdateRequests') && POIs[n].attributes.venueUpdateRequests.length >> 0) {
          PURs.push(POIs[n].attributes)
        }
      }
      const urcount = URs.length
      const mpcount = MPs.length
      const mccount = MCs.length
      const purcount = PURs.length
      const count = urcount + mpcount + mccount + purcount
      WMEURMPT.log('new data available: i/count:' + i + '/' + count)
      if (i === 0) {
        WMEURMPT.log('Starting WME data scan...')
        pb.update(0)
        pb.show()
        WMEURMPT.showPBInfo(true)
        WMEURMPT.info('Scanning...')
      }
      if (i >= count) {
        WMEURMPT.log('WME data scan ended')
        WMEURMPT.updateRequestSessions()
        WMEURMPT.isScanningWME = false
        WMEURMPT.showPBInfo(false)
        pb.hide()
        pb.update(0)
        WMEURMPT.info()
        WMEURMPT.updateIHMFromURList()
        WMEURMPT.updateIHMFromMPList()
        WMEURMPT.updateIHMFromMCList()
        WMEURMPT.updateIHMFromPURList()
        WMEURMPT.saveURMPLists()
        return
      }
      pb.update(Math.round(i / count * 100))
      if (i < urcount) {
        const index = i
        const URId = URs[index].attributes.id
        let theUR = WMEURMPT.getURFromId(URId)
        if (WMEURMPT.ul < WMEURMPT.rl4cp && URs[index].attributes.open === false) {
          if (theUR != null) {
            WMEURMPT.URList.splice(WMEURMPT.URMap[URId], 1)
            WMEURMPT.URMap = WMEURMPT.listToObject(WMEURMPT.URList)
          }
        } else {
          WMEURMPT.logDebug('scan WME: the ur: ', theUR)
          WMEURMPT.logDebug('scan WME: the ur index: ', URs[index])
          const URxy = new OpenLayers.Geometry.Point(URs[index].geometry.x, URs[index].geometry.y)
          const URLonlat = OpenLayers.Layer.SphericalMercator.inverseMercator(URs[index].geometry.x, URs[index].geometry.y)
          if (WMEURMPT.inScreenUpdatableArea(URxy) || WMEURMPT.isInAreas(URLonlat)) {
            WMEURMPT.logDebug('scan WME: in screen')
            if (theUR == null) {
              theUR = new WMEURMPT.URT_UR(URs[index].attributes.id, URLonlat.lon, URLonlat.lat)
              if (theUR.refreshFromWMEData(false)) {
                WMEURMPT.logDebug('scan WME: added')
                WMEURMPT.URList.push(theUR)
                WMEURMPT.URMap = WMEURMPT.listToObject(WMEURMPT.URList)
              } else {
                WMEURMPT.logDebug('scan WME: NOT added')
              }
            } else {
              theUR.refreshFromWMEData(false)
            }
          } else {
            if (theUR != null) {
              WMEURMPT.URList.splice(WMEURMPT.URMap[URId], 1)
              WMEURMPT.URMap = WMEURMPT.listToObject(WMEURMPT.URList)
            }
          }
        }
      } else {
        if (i - urcount < mpcount) {
          const index = i - urcount
          const MPId = MPs[index].attributes.id
          let theMP = WMEURMPT.getMPFromId(MPId)
          if (WMEURMPT.ul < WMEURMPT.rl4cp && MPs[index].attributes.open === false) {
            if (theMP != null) {
              WMEURMPT.MPList.splice(WMEURMPT.MPMap[MPId], 1)
              WMEURMPT.MPMap = WMEURMPT.listToObject(WMEURMPT.MPList)
            }
          } else {
            const MPxy = new OpenLayers.Geometry.Point(MPs[index].geometry.x, MPs[index].geometry.y)
            const MPLonlat = OpenLayers.Layer.SphericalMercator.inverseMercator(MPs[index].geometry.x, MPs[index].geometry.y)
            if (WMEURMPT.inScreenUpdatableArea(MPxy) || WMEURMPT.isInAreas(MPLonlat)) {
              if (theMP == null) {
                theMP = new WMEURMPT.URT_MP(MPs[index].attributes.id, MPLonlat.lon, MPLonlat.lat)
                if (theMP.refreshFromWMEData()) {
                  WMEURMPT.MPList.push(theMP)
                  WMEURMPT.MPMap = WMEURMPT.listToObject(WMEURMPT.MPList)
                }
              } else {
                theMP.refreshFromWMEData()
              }
            } else {
              if (theMP != null) {
                WMEURMPT.MPList.splice(WMEURMPT.MPMap[MPId], 1)
                WMEURMPT.MPMap = WMEURMPT.listToObject(WMEURMPT.MPList)
              }
            }
          }
        } else {
          if (i - urcount - mpcount < mccount) {
            const index = i - urcount - mpcount
            const MCId = MCs[index].attributes.id
            let theMC = WMEURMPT.getMCFromId(MCId)
            const MCxy = new OpenLayers.Geometry.Point(MCs[index].geometry.getCentroid().x, MCs[index].geometry.getCentroid().y)
            const MCLonlat = OpenLayers.Layer.SphericalMercator.inverseMercator(MCs[index].geometry.getCentroid().x, MCs[index].geometry.getCentroid().y)
            if (WMEURMPT.inScreenUpdatableArea(MCxy) || WMEURMPT.isInAreas(MCLonlat)) {
              WMEURMPT.log('in area')
              if (theMC == null) {
                theMC = new WMEURMPT.URT_MC(MCs[index].attributes.id, MCLonlat.lon, MCLonlat.lat)
                if (theMC.refreshFromWMEData()) {
                  WMEURMPT.MCList.push(theMC)
                  WMEURMPT.MCMap = WMEURMPT.listToObject(WMEURMPT.MPList)
                }
              } else {
                theMC.refreshFromWMEData()
              }
            } else {
              WMEURMPT.log('not in area')
              if (theMC != null) {
                WMEURMPT.MCList.splice(WMEURMPT.MCMap[MCId], 1)
                WMEURMPT.MCMap = WMEURMPT.listToObject(WMEURMPT.MCList)
              }
            }
          } else {
            const index = i - urcount - mpcount - mccount
            const PURId = PURs[index].id
            let thePUR = WMEURMPT.getPURFromId(PURId)
            const PURxy = new OpenLayers.Geometry.Point(PURs[index].geometry.getCentroid().x, PURs[index].geometry.getCentroid().y)
            const PURLonlat = OpenLayers.Layer.SphericalMercator.inverseMercator(PURs[index].geometry.getCentroid().x, PURs[index].geometry.getCentroid().y)
            if (WMEURMPT.inScreenUpdatableArea(PURxy) || WMEURMPT.isInAreas(PURLonlat)) {
              WMEURMPT.log('in area')
              if (thePUR == null) {
                thePUR = new WMEURMPT.URT_PUR(PURs[index].id, PURLonlat.lon, PURLonlat.lat)
                if (thePUR.refreshFromWMEData()) {
                  WMEURMPT.PURList.push(thePUR)
                  WMEURMPT.PURMap = WMEURMPT.listToObject(WMEURMPT.PURList)
                }
              } else {
                thePUR.refreshFromWMEData()
              }
            } else {
              WMEURMPT.log('not in area')
              if (thePUR != null) {
                WMEURMPT.PURList.splice(WMEURMPT.PURMap[PURId], 1)
                WMEURMPT.PURMap = WMEURMPT.listToObject(WMEURMPT.PURList)
              }
            }
          }
        }
      }
      i++
      window.setTimeout(WMEURMPT.getFunctionWithArgs(WMEURMPT.newDataAvailable, [i]), 0)
    } catch (err) {
      WMEURMPT.log('Warning during auto scan probably due to a map move or a map zoom changed before end of scan: ', err)
      WMEURMPT.isScanningWME = false
      WMEURMPT.showPBInfo(false)
      pb.hide()
      pb.update(0)
      WMEURMPT.info()
      window.setTimeout(WMEURMPT.newDataAvailableStarts, 1000)
    }
  }

  WMEURMPT.onProblemsShown = function (e) {
    WMEURMPT.logDebug('prob shown, type: ' + e.type)
    WMEURMPT.clickUR(e)
  }

  WMEURMPT.setupListener = function () {
    const urs = W.map.getLayerByName('update_requests').features
    for (let i = 0; i < urs.length; i++) {
      const urx = urs[i].attributes.wazeFeature.id
      const urModel = W.model.mapUpdateRequests.getObjectById(urx)
      if (urModel) {
        const urel = W.userscripts.getFeatureElementByDataModel(urModel)
        if (urel) {
          urel.addEventListener('click', WMEURMPT.clickUR, false)
        }
      }
    }
    const purs = WMEURMPT.getElementsByClassName('place-update')
    for (let i = 0; i < purs.length; i++) {
      const pur = purs[i]
      pur.addEventListener('click', WMEURMPT.clickPUR, false)
    }
  }

  WMEURMPT.URJustOpened = function (urId) {
    WMEURMPT.currentURID = urId
    WMEURMPT.URVisited(WMEURMPT.currentURID)
    WMEURMPT.logDebug('current UR ID: ' + WMEURMPT.currentURID)
    WMEURMPT.setupFollowAndSendListner()
    WMEURMPT.selectedURID = WMEURMPT.currentURID
    WMEURMPT.log('UR clicked: ' + WMEURMPT.currentURID)
    let ur = WMEURMPT.getURFromId(WMEURMPT.currentURID)
    WMEURMPT.logDebug('clickUR ur: ', ur)
    if (ur) {
      ur.refreshFromWMEData()
    } else if (ur == null) {
      const theUR = WMEURMPT.wazeModel.mapUpdateRequests.getObjectById(WMEURMPT.currentURID)
      let URLonlat = null
      WMEURMPT.logDebug('clickUR - theUR: ', theUR)
      if (Object.prototype.hasOwnProperty.call(theUR.geometry, 'realX') && Object.prototype.hasOwnProperty.call(theUR.geometry, 'realY')) {
        URLonlat = OpenLayers.Layer.SphericalMercator.inverseMercator(theUR.geometry.realX, theUR.geometry.realY)
      } else {
        URLonlat = OpenLayers.Layer.SphericalMercator.inverseMercator(theUR.geometry.x, theUR.geometry.y)
      }
      WMEURMPT.logDebug('clickUR - lonlat: ', URLonlat)
      ur = new WMEURMPT.URT_UR(theUR.attributes.id, URLonlat.lon, URLonlat.lat)
      WMEURMPT.logDebug('clickUR - ur: ', ur)
      if (ur.refreshFromWMEData()) {
        WMEURMPT.URList.push(ur)
        WMEURMPT.URMap = WMEURMPT.listToObject(WMEURMPT.URList)
      }
    }
    WMEURMPT.updateIHMFromURList()
  }

  WMEURMPT.clickUR = function (e) {
    let id = 0
    if (e.type === 'mapUpdateRequest') {
      id = e.attributes.id
    } else if (typeof this.tagName !== 'undefined' && this.tagName === 'image') {
      const mod = W.userscripts.getDataModelByFeatureElement(this)
      id = mod.attributes.id
    }
    if (id > 0) {
      WMEURMPT.URJustOpened(id)
    }
  }

  WMEURMPT.clickPUR = function () {
    WMEURMPT.logDebug('PUR clicked: ', this)
    WMEURMPT.currentPURID = W.selectionManager.getSelectedWMEFeatures()[0].id
    WMEURMPT.selectedPURID = WMEURMPT.currentPURID
    WMEURMPT.PURVisited(WMEURMPT.currentPURID)
    WMEURMPT.log('PUR clicked: ' + WMEURMPT.currentPURID, this)
    let pur = WMEURMPT.getPURFromId(WMEURMPT.currentPURID)
    if (pur) {
      pur.refreshFromWMEData()
    } else if (pur == null) {
      const thePUR = WMEURMPT.wazeModel.venues.objects[WMEURMPT.currentPURID]
      const lonlat = OpenLayers.Layer.SphericalMercator.inverseMercator(thePUR.attributes.geometry.getCentroid().x, thePUR.attributes.geometry.getCentroid().y)
      WMEURMPT.logDebug('clickPUR - lonlat: ', lonlat)
      pur = new WMEURMPT.URT_PUR(thePUR.attributes.id, lonlat.lon, lonlat.lat)
      WMEURMPT.logDebug('clickPUR - pur: ', pur)
      if (pur.refreshFromWMEData()) {
        WMEURMPT.PURList.push(pur)
        WMEURMPT.PURMap = WMEURMPT.listToObject(WMEURMPT.PURList)
      }
    }
    WMEURMPT.updateIHMFromPURList()
  }

  WMEURMPT.getNewMC = function (mcID) {
    WMEURMPT.currentMCID = mcID
    WMEURMPT.selectedMCID = WMEURMPT.currentMCID
    WMEURMPT.MCVisited(WMEURMPT.currentMCID)
    WMEURMPT.log('New MC: ' + WMEURMPT.currentMCID)
    let mc = WMEURMPT.getMCFromId(WMEURMPT.currentMCID)
    if (mc) {
      mc.refreshFromWMEData()
    } else if (mc == null) {
      const theMC = WMEURMPT.wazeModel.mapComments.objects[WMEURMPT.currentMCID]
      const lonlat = OpenLayers.Layer.SphericalMercator.inverseMercator(theMC.attributes.geometry.getCentroid().x, theMC.attributes.geometry.getCentroid().y)
      mc = new WMEURMPT.URT_MC(theMC.attributes.id, lonlat.lon, lonlat.lat)
      if (mc.refreshFromWMEData()) {
        WMEURMPT.MCList.push(mc)
        WMEURMPT.MCMap = WMEURMPT.listToObject(WMEURMPT.MCList)
      }
    }
    WMEURMPT.updateIHMFromMCList()
  }

  WMEURMPT.setupFollowAndSendListner = function () {
    let sendPatched = false
    const btnFollow = document.getElementsByName('follow')[0]
    if (btnFollow != null) {
      if (typeof btnFollow.urt_listener === 'undefined') {
        btnFollow.addEventListener('change', WMEURMPT.clickFollowUR, false)
        btnFollow.urt_listener = true
      }
    }
    const commentForm = WMEURMPT.getElementsByClassName('new-comment-form')[0]
    const btnsSend = WMEURMPT.getElementsByClassName('send-button', commentForm)
    if (btnsSend.length === 1) {
      const btnSend = btnsSend[0]
      if (typeof btnSend.urt_listener === 'undefined') {
        btnSend.addEventListener('click', function () {
          window.setTimeout(WMEURMPT.conversationSent, 400)
        }, false)
        btnSend.urt_listener = true
        sendPatched = true
      } else {
        sendPatched = true
      }
    }
    if (!sendPatched) {
      window.setTimeout(WMEURMPT.setupFollowAndSendListner, 200)
    }
  }

  WMEURMPT.conversationSent = function () {
    const ur = WMEURMPT.getURFromId(WMEURMPT.currentURID)
    if (ur !== null) {
      WMEURMPT.log('update Comment and refresh...')
      ur.refreshFromWMEData(true)
      ur.lastVisitCommentsCount = ur.data.session.comments.length
      WMEURMPT.updateIHMFromURList()
    }
  }

  WMEURMPT.clickFollowUR = function () {
    WMEURMPT.logDebug('FOLLOW or UNFOLLOW. That is the question')
    if (!this.checked) {
      WMEURMPT.log('Now: unfollow ' + WMEURMPT.currentURID)
      const ur = WMEURMPT.getURFromId(WMEURMPT.currentURID)
      if (ur != null) {
        ur.data.session.isFollowing = false
        WMEURMPT.updateIHMFromURList()
      }
    } else {
      WMEURMPT.log('Now: follow ' + WMEURMPT.currentURID)
      const ur = WMEURMPT.getURFromId(WMEURMPT.currentURID)
      if (ur != null) {
        ur.data.session.isFollowing = true
        WMEURMPT.URBlackListed(WMEURMPT.currentURID, false)
        WMEURMPT.URVisited(WMEURMPT.currentURID)
        WMEURMPT.updateIHMFromURList()
      }
    }
  }

  WMEURMPT.openConversationPannel = function () {
    const btnConversations = WMEURMPT.getElementsByClassName('btn btn-default toggle-comment-view')
    if (btnConversations.length !== 1) {
      window.setTimeout(WMEURMPT.openConversationPannel, 100)
      return
    }
    const btnConversation = btnConversations[0]
    if (btnConversation.className === 'btn btn-default toggle-comment-view comment-view-shown') {
      return
    }
    btnConversation.click()
  }

  WMEURMPT.saveStarted = function () {
    WMEURMPT.visitedURBeforeActionsSaved.length = 0
    WMEURMPT.visitedMPBeforeActionsSaved.length = 0
    WMEURMPT.visitedTPBeforeActionsSaved.length = 0
    WMEURMPT.visitedPURBeforeActionsSaved.length = 0
    const actions = WMEURMPT.wazeModel.actionManager.getActions()
    for (let i = 0; i < actions.length; i++) {
      if (actions[i].CLASS_NAME === 'Waze.Action.UpdateRequest') {
        WMEURMPT.visitedURBeforeActionsSaved.push(actions[i].request.attributes.id)
      }
      if (actions[i].CLASS_NAME === 'Waze.Action.UpdateProblem') {
        if (actions[i].problem.type === 'mapProblem') {
          WMEURMPT.visitedMPBeforeActionsSaved.push(actions[i].problem.attributes.id)
        }
        if (actions[i].problem.type !== 'mapProblem' && actions[i].problem.type !== 'turnProblem') {
          WMEURMPT.log('Error while detecting update problem operation on: ', WMEURMPT.wazeModel.actionManager.actions[i])
        }
      }
    }
  }

  WMEURMPT.saveEnded = function () {
    for (let i = 0; i < WMEURMPT.visitedURBeforeActionsSaved.length; i++) {
      WMEURMPT.log('save UR: ' + WMEURMPT.visitedURBeforeActionsSaved[i])
      const ur = WMEURMPT.getURFromId(WMEURMPT.visitedURBeforeActionsSaved[i])
      if (ur != null) {
        WMEURMPT.logDebug('save UR Action: id=' + WMEURMPT.visitedURBeforeActionsSaved[i] + ' found')
        let refreshStatus = ur.refreshFromWMEData(true)
        if (!refreshStatus) {
          refreshStatus = ur.refreshFromServer()
          if (refreshStatus === true || refreshStatus === null) {
            WMEURMPT.logDebug('save UR Action: id=' + WMEURMPT.visitedURBeforeActionsSaved[i] + ' refresh ok: ' + refreshStatus)
            ur.blackListed = false
            ur.alreadyVisited = true
          } else {
            WMEURMPT.logDebug('save UR Action: id=' + WMEURMPT.visitedURBeforeActionsSaved[i] + ' No change found')
          }
        }
      } else {
        WMEURMPT.logDebug('save UR Action: id=' + WMEURMPT.visitedURBeforeActionsSaved[i] + ' not found')
      }
    }
    for (let i = 0; i < WMEURMPT.visitedMPBeforeActionsSaved.length; i++) {
      WMEURMPT.log('save MP: ' + WMEURMPT.visitedMPBeforeActionsSaved[i])
      const mp = WMEURMPT.getMPFromId(WMEURMPT.visitedMPBeforeActionsSaved[i])
      if (mp != null) {
        WMEURMPT.logDebug('save MP Action: id=' + WMEURMPT.visitedMPBeforeActionsSaved[i] + ' found')
        let refreshStatus = mp.refreshFromWMEData()
        if (!refreshStatus) {
          refreshStatus = mp.refreshFromServer()
          if (refreshStatus === true || refreshStatus === null) {
            WMEURMPT.logDebug('save MP Action: id=' + WMEURMPT.visitedMPBeforeActionsSaved[i] + ' refresh ok: ' + refreshStatus)
            mp.blackListed = false
            mp.alreadyVisited = true
          } else {
            WMEURMPT.logDebug('save MP Action: id=' + WMEURMPT.visitedMPBeforeActionsSaved[i] + ' No change found')
          }
        }
      } else {
        WMEURMPT.logDebug('save MP Action: id=' + WMEURMPT.visitedMPBeforeActionsSaved[i] + ' not found')
      }
    }
    for (let i = 0; i < WMEURMPT.visitedTPBeforeActionsSaved.length; i++) {
      WMEURMPT.log('save MP (TP): ' + WMEURMPT.visitedTPBeforeActionsSaved[i])
      const mp = WMEURMPT.getMPFromId(WMEURMPT.visitedTPBeforeActionsSaved[i])
      if (mp != null) {
        WMEURMPT.logDebug('save TP Action: id=' + WMEURMPT.visitedTPBeforeActionsSaved[i] + ' found')
        let refreshStatus = mp.refreshFromWMEData()
        if (!refreshStatus) {
          refreshStatus = mp.refreshFromServer()
          if (refreshStatus === true || refreshStatus === null) {
            WMEURMPT.logDebug('save TP Action: id=' + WMEURMPT.visitedTPBeforeActionsSaved[i] + ' refresh ok: ' + refreshStatus)
            mp.blackListed = false
            mp.alreadyVisited = true
          } else {
            WMEURMPT.logDebug('save TP Action: id=' + WMEURMPT.visitedTPBeforeActionsSaved[i] + ' No change found')
          }
        }
      } else {
        WMEURMPT.logDebug('save TP Action: id=' + WMEURMPT.visitedTPBeforeActionsSaved[i] + ' not found')
      }
    }
    WMEURMPT.updateIHMFromURList()
    WMEURMPT.updateIHMFromMPList()
  }

  WMEURMPT.newActionAdded = function (lastAction) {
    WMEURMPT.logDebug('Action added:', lastAction)
    lastAction = lastAction.action
    WMEURMPT.logDebug('Action added lastAction :', lastAction)
    if (Object.prototype.hasOwnProperty.call(lastAction, 'object') && Object.prototype.hasOwnProperty.call(lastAction.object, 'type') && lastAction.object.type === 'mapProblem') {
      const mp = WMEURMPT.getMPFromId(lastAction.object.attributes.id)
      if (mp == null) {
        return
      }
      mp.refreshFromWMEData()
      if (mp.data.open === true) {
        mp.data.resolvedOn = null
        mp.data.resolvedBy = null
        mp.data.resolvedByName = null
      } else {
        const now = new Date()
        mp.data.resolvedOn = now.getTime()
        mp.data.resolvedBy = WMEURMPT.me.getID()
        mp.data.resolvedByName = WMEURMPT.me.getUsername()
      }
      WMEURMPT.updateIHMFromMPList()
    }
    if (Object.prototype.hasOwnProperty.call(lastAction, 'object') && Object.prototype.hasOwnProperty.call(lastAction.object, 'type') && lastAction.object.type === 'mapUpdateRequest') {
      const ur = WMEURMPT.getURFromId(lastAction.object.attributes.id)
      if (ur == null) {
        return
      }
      ur.refreshFromWMEData(true)
      if (ur.data.open === true) {
        ur.data.resolvedOn = null
        ur.data.resolvedBy = null
        ur.data.resolvedByName = null
      } else {
        const now = new Date()
        ur.data.resolvedOn = now.getTime()
        ur.data.resolvedBy = WMEURMPT.me.getID()
        ur.data.resolvedByName = WMEURMPT.me.getUsername()
      }
      WMEURMPT.updateIHMFromURList()
    }
    if (Object.prototype.hasOwnProperty.call(lastAction, 'request') && Object.prototype.hasOwnProperty.call(lastAction.request.attributes, 'approved')) {
      let pur = WMEURMPT.getPURFromId(lastAction.venue.attributes.id)
      if (pur) {
        pur.refreshFromWMEData()
      }
      if (pur === null) {
        const lonlat = OpenLayers.Layer.SphericalMercator.inverseMercator(lastAction.venue.attributes.geometry.getCentroid().x, lastAction.venue.attributes.geometry.getCentroid().y)
        pur = new WMEURMPT.URT_PUR(lastAction.venue.attributes.id, lonlat.lon, lonlat.lat)
        if (pur.refreshFromWMEData()) {
          WMEURMPT.PURList.push(pur)
          WMEURMPT.PURMap = WMEURMPT.listToObject(WMEURMPT.PURList)
        }
      }
      WMEURMPT.updateIHMFromPURList()
    }
    if (Object.prototype.hasOwnProperty.call(lastAction, 'object') && Object.prototype.hasOwnProperty.call(lastAction.object, 'type') && lastAction.object.type === 'mapComment') {
      if (typeof lastAction.object.attributes.id === 'string') {
        let mc = WMEURMPT.getMCFromId(lastAction.object.attributes.id)
        if (mc) {
          mc.refreshFromWMEData()
        }
        if (mc === null) {
          const xyGeom = W.userscripts.toOLGeometry(lastAction.object.attributes.geometry)
          const xy = new OpenLayers.Geometry.Point(xyGeom.getBounds().getCenterLonLat().lon, xyGeom.getBounds().getCenterLonLat().lat)
          const lonlat = OpenLayers.Layer.SphericalMercator.inverseMercator(xy.x, xy.y)
          mc = new WMEURMPT.URT_MC(lastAction.object.attributes.id, lonlat.lon, lonlat.lat)
          if (mc.refreshFromWMEData()) {
            WMEURMPT.MCList.push(mc)
            WMEURMPT.MCMap = WMEURMPT.listToObject(WMEURMPT.MCList)
          }
        }
        WMEURMPT.updateIHMFromMCList()
      }
    }
  }

  WMEURMPT.getMPs = function (bounds, filter) {
    const url = 'https://' + document.location.host + WMEURMPT.wazeConfigApiFeatures + '?language=en' + (WMEURMPT.scanUR ? '&mapUpdateRequestFilter=3%2C0' : '') + (WMEURMPT.scanMP ? '&problemFilter=3%2C3' : '') + '&mapComments=' + (WMEURMPT.scanMC ? 'true' : 'false') + '&venueLevel=3&venueFilter=' + (WMEURMPT.scanPUR ? '3%2C3%2C3' : '0%2C0%2C0') + '&editableAreas=true&bbox=' + bounds.left + '%2C' + bounds.bottom + '%2C' + bounds.right + '%2C' + bounds.top
    let xhr3Object = null
    if (XMLHttpRequest) {
      xhr3Object = new XMLHttpRequest()
    } else if (ActiveXObject) {
      xhr3Object = new ActiveXObject('Microsoft.XMLHTTP')
    }
    let MPs = null
    xhr3Object.open('GET', url, false)
    xhr3Object.send(null)
    if (xhr3Object.status === 200) {
      const r = xhr3Object.responseText
      try {
        MPs = JSON.parse(r)
      } catch (e) {
        WMEURMPT.log("Error: can't read server response: ", e)
        WMEURMPT.log('Response from server: ', r)
        WMEURMPT.log('Query: ', url)
        MPs = null
      }
    }
    if (MPs == null) {
      return null
    }
    if (!Object.prototype.hasOwnProperty.call(MPs, 'mapUpdateRequests') && !Object.prototype.hasOwnProperty.call(MPs, 'problems') && !Object.prototype.hasOwnProperty.call(MPs, 'mapComments') && !Object.prototype.hasOwnProperty.call(MPs, 'venues')) {
      return null
    }
    if (Object.prototype.hasOwnProperty.call(MPs, 'mapUpdateRequests') && MPs.mapUpdateRequests.objects.length === 500) {
      return { error: 1, logMessage: { obj: 'mapUpdateRequests', length: 500 } }
    }
    if (Object.prototype.hasOwnProperty.call(MPs, 'problems') && MPs.problems.objects.length === 500) {
      return { error: 1, logMessage: { obj: 'problems', length: 500 } }
    }
    if (Object.prototype.hasOwnProperty.call(MPs, 'mapComments') && MPs.mapComments.objects.length === 500) {
      return { error: 1, logMessage: { obj: 'mapComments', length: 500 } }
    }
    if (Object.prototype.hasOwnProperty.call(MPs, 'venues') && MPs.venues.objects.length >= 1200) {
      return { error: 1, logMessage: { obj: 'venues', length: 1200 } }
    }
    if (filter != null) {
      let filterArea = []
      if (filter != null && (filter.type === 'editableArea' || filter.type === 'driveArea' || filter.type === 'managedArea')) {
        for (let a = 0; a < MPs.userAreas.objects.length; a++) {
          filterArea = filterArea.concat(WMEURMPT.wazeMapAreaToOLPolygons(MPs.userAreas.objects[a].geometry))
        }
      }
      if (filter != null && filter.type === 'country') {
        for (let c = 0; c < WMEURMPT.areaList.country.length; c++) {
          if (WMEURMPT.areaList.country[c].name === filter.name) {
            filterArea = WMEURMPT.areaList.country[c].geometryOL.geometry.components
            break
          }
        }
      }
      if (filter !== null && filter.type === 'custom') {
        for (let c = 0; c < WMEURMPT.areaList.custom.length; c++) {
          if (WMEURMPT.areaList.custom[c].name === filter.name) {
            filterArea = WMEURMPT.areaList.custom[c].geometryOL.geometry.components
            break
          }
        }
      }
      let cmp = 0
      if (Object.prototype.hasOwnProperty.call(MPs, 'problems')) {
        while (cmp < MPs.problems.objects.length) {
          const theMP = MPs.problems.objects[cmp]
          if (WMEURMPT.ul < WMEURMPT.rl4cp && theMP.open === false) {
            MPs.problems.objects.splice(cmp, 1)
            continue
          }
          const lonlat = OpenLayers.Layer.SphericalMercator.forwardMercator(theMP.geometry.coordinates[0], theMP.geometry.coordinates[1])
          let xy = new OpenLayers.Geometry.Point(lonlat.lon, lonlat.lat)
          if (filter.type === 'country' || filter.type === 'custom') {
            xy = new OpenLayers.Geometry.Point(theMP.geometry.coordinates[0], theMP.geometry.coordinates[1])
          }
          let inside = false
          for (let a = 0; a < filterArea.length; a++) {
            if (Object.prototype.hasOwnProperty.call(filterArea[a], 'bintreeContainsPoint') === false) {
              if (xy.x >= filterArea[a].bounds.left && xy.x <= filterArea[a].bounds.right && xy.y >= filterArea[a].bounds.bottom && xy.y <= filterArea[a].bounds.top && filterArea[a].containsPoint(xy)) {
                inside = true
                break
              }
            } else {
              if (filterArea[a].bintreeContainsPoint(xy)) {
                inside = true
                break
              }
            }
          }
          if (!inside) {
            MPs.problems.objects.splice(cmp, 1)
            continue
          }
          cmp++
        }
      }
      cmp = 0
      if (Object.prototype.hasOwnProperty.call(MPs, 'mapUpdateRequests')) {
        while (cmp < MPs.mapUpdateRequests.objects.length) {
          const theUR = MPs.mapUpdateRequests.objects[cmp]
          const skipType = [18, 23]
          if (skipType.includes(theUR.type)) {
            MPs.mapUpdateRequests.objects.splice(cmp, 1)
            continue
          }
          if (WMEURMPT.ul < WMEURMPT.rl4cp && theUR.open === false) {
            MPs.mapUpdateRequests.objects.splice(cmp, 1)
            continue
          }
          const lonlat = OpenLayers.Layer.SphericalMercator.forwardMercator(theUR.geometry.coordinates[0], theUR.geometry.coordinates[1])
          let xy = new OpenLayers.Geometry.Point(lonlat.lon, lonlat.lat)
          if (filter.type === 'country' || filter.type === 'custom') {
            xy = new OpenLayers.Geometry.Point(theUR.geometry.coordinates[0], theUR.geometry.coordinates[1])
          }
          let inside = false
          for (let a = 0; a < filterArea.length; a++) {
            if (Object.prototype.hasOwnProperty.call(filterArea[a], 'bintreeContainsPoint') === false) {
              if (xy.x >= filterArea[a].bounds.left && xy.x <= filterArea[a].bounds.right && xy.y >= filterArea[a].bounds.bottom && xy.y <= filterArea[a].bounds.top && filterArea[a].containsPoint(xy)) {
                inside = true
                break
              }
            } else {
              if (filterArea[a].bintreeContainsPoint(xy)) {
                inside = true
                break
              }
            }
          }
          if (!inside) {
            MPs.mapUpdateRequests.objects.splice(cmp, 1)
            continue
          }
          cmp++
        }
      }
      cmp = 0
      if (Object.prototype.hasOwnProperty.call(MPs, 'mapComments')) {
        while (cmp < MPs.mapComments.objects.length) {
          const theMC = MPs.mapComments.objects[cmp]
          let lonlat = null
          let centroid = null
          if (theMC.geometry.type === 'Point') {
            lonlat = OpenLayers.Layer.SphericalMercator.forwardMercator(theMC.geometry.coordinates[0], theMC.geometry.coordinates[1])
          } else {
            const olpolys = []
            theMC.geometry.coordinates.forEach(function (poly) {
              const olpts = poly.map(function (e) {
                return new OpenLayers.Geometry.Point(e[0], e[1])
              })
              const ollr = new OpenLayers.Geometry.LinearRing(olpts)
              const olp = new OpenLayers.Geometry.Polygon(ollr)
              olpolys.push(olp)
            })
            const olmultipoly = new OpenLayers.Geometry.MultiPolygon(olpolys)
            centroid = olmultipoly.getCentroid()
            lonlat = OpenLayers.Layer.SphericalMercator.forwardMercator(centroid.x, centroid.y)
          }
          let xy = new OpenLayers.Geometry.Point(lonlat.lon, lonlat.lat)
          if (filter.type === 'country' || filter.type === 'custom') {
            if (theMC.geometry.type === 'Point') {
              xy = new OpenLayers.Geometry.Point(theMC.geometry.coordinates[0], theMC.geometry.coordinates[1])
            } else {
              xy = centroid
            }
          }
          let inside = false
          for (let a = 0; a < filterArea.length; a++) {
            if (Object.prototype.hasOwnProperty.call(filterArea[a], 'bintreeContainsPoint') === false) {
              if (xy.x >= filterArea[a].bounds.left && xy.x <= filterArea[a].bounds.right && xy.y >= filterArea[a].bounds.bottom && xy.y <= filterArea[a].bounds.top && filterArea[a].containsPoint(xy)) {
                inside = true
                break
              }
            } else {
              if (filterArea[a].bintreeContainsPoint(xy)) {
                inside = true
                break
              }
            }
          }
          if (!inside) {
            MPs.mapComments.objects.splice(cmp, 1)
            continue
          }
          cmp++
        }
      }
      cmp = 0
      if (Object.prototype.hasOwnProperty.call(MPs, 'venues')) {
        while (cmp < MPs.venues.objects.length) {
          const thePUR = MPs.venues.objects[cmp]
          if (!Object.prototype.hasOwnProperty.call(thePUR, 'venueUpdateRequests')) {
            MPs.venues.objects.splice(cmp, 1)
            continue
          }
          if (thePUR.venueUpdateRequests.length === 0) {
            MPs.venues.objects.splice(cmp, 1)
            continue
          }
          let lonlat = null
          let centroid = null
          if (thePUR.geometry.type === 'Point') {
            lonlat = OpenLayers.Layer.SphericalMercator.forwardMercator(thePUR.geometry.coordinates[0], thePUR.geometry.coordinates[1])
          } else {
            const olpolys = []
            thePUR.geometry.coordinates.forEach(function (poly) {
              const olpts = poly.map(function (e) {
                return new OpenLayers.Geometry.Point(e[0], e[1])
              })
              const ollr = new OpenLayers.Geometry.LinearRing(olpts)
              const olp = new OpenLayers.Geometry.Polygon(ollr)
              olpolys.push(olp)
            })
            const olmultipoly = new OpenLayers.Geometry.MultiPolygon(olpolys)
            centroid = olmultipoly.getCentroid()
            lonlat = OpenLayers.Layer.SphericalMercator.forwardMercator(centroid.x, centroid.y)
          }
          let xy = new OpenLayers.Geometry.Point(lonlat.lon, lonlat.lat)
          if (filter.type === 'country' || filter.type === 'custom') {
            if (thePUR.geometry.type === 'Point') {
              xy = new OpenLayers.Geometry.Point(thePUR.geometry.coordinates[0], thePUR.geometry.coordinates[1])
            } else {
              xy = centroid
            }
          }
          let inside = false
          for (let a = 0; a < filterArea.length; a++) {
            if (Object.prototype.hasOwnProperty.call(filterArea[a], 'bintreeContainsPoint') === false) {
              if (xy.x >= filterArea[a].bounds.left && xy.x <= filterArea[a].bounds.right && xy.y >= filterArea[a].bounds.bottom && xy.y <= filterArea[a].bounds.top && filterArea[a].containsPoint(xy)) {
                inside = true
                break
              }
            } else {
              if (filterArea[a].bintreeContainsPoint(xy)) {
                inside = true
                break
              }
            }
          }
          if (!inside) {
            MPs.venues.objects.splice(cmp, 1)
            continue
          }
          cmp++
        }
      }
      MPs.area = filterArea
      MPs.filterType = filter.type
      MPs.tile = bounds
    }
    if (Object.prototype.hasOwnProperty.call(MPs, 'mapUpdateRequests')) {
      const urIds = []
      for (let i = 0; i < MPs.mapUpdateRequests.objects.length; i++) {
        urIds.push(MPs.mapUpdateRequests.objects[i].id)
      }
      if (urIds.length !== 0) {
        const url = 'https://' + document.location.host + WMEURMPT.wazeConfigApiUpdateRequestSessions + '?ids=' + urIds.join(',')
        if (XMLHttpRequest) {
          xhr3Object = new XMLHttpRequest()
        } else if (ActiveXObject) {
          xhr3Object = new ActiveXObject('Microsoft.XMLHTTP')
        }
        let URcomments = null
        xhr3Object.open('GET', url, false)
        xhr3Object.ontimeout = function () {
          URcomments = null
        }
        xhr3Object.onerror = function () {
          URcomments = null
        }
        xhr3Object.onreadystatechange = function () {
          if (xhr3Object.readyState === 4) {
            const r = xhr3Object.responseText
            try {
              URcomments = JSON.parse(r)
            } catch (e$0) {
              WMEURMPT.log("Error: can't read server response: ", e$0)
              WMEURMPT.log('Response from server: ', r)
              WMEURMPT.log('Query: ', url)
              URcomments = null
            }
          } else {
            URcomments = null
          }
        }
        xhr3Object.send(null)
        WMEURMPT.logDebug('UR comments: ', URcomments)
        if (URcomments == null) {
          return null
        }
        for (let i = 0; i < MPs.mapUpdateRequests.objects.length; i++) {
          const urId = MPs.mapUpdateRequests.objects[i].id
          for (let j = 0; j < URcomments.updateRequestSessions.objects.length; j++) {
            if (urId === URcomments.updateRequestSessions.objects[j].id) {
              MPs.mapUpdateRequests.objects[i].session = URcomments.updateRequestSessions.objects[j]
              MPs.mapUpdateRequests.objects[i].session.users = URcomments.users
              break
            }
          }
        }
      }
    }
    WMEURMPT.logDebug('URs, MPs, MCs, and PURs from server after process: ', MPs)
    return MPs
  }

  WMEURMPT.updateURList = function (URs) {
    if (Object.prototype.hasOwnProperty.call(URs, 'mapUpdateRequests') === false) {
      return
    }
    for (let i = 0; i < URs.mapUpdateRequests.objects.length; i++) {
      let found = true
      let ur = WMEURMPT.getURFromId(URs.mapUpdateRequests.objects[i].id)
      if (ur == null) {
        ur = new WMEURMPT.URT_UR(URs.mapUpdateRequests.objects[i].id, URs.mapUpdateRequests.objects[i].geometry.coordinates[0], URs.mapUpdateRequests.objects[i].geometry.coordinates[1])
        found = false
      }
      ur.data = JSON.parse(JSON.stringify(URs.mapUpdateRequests.objects[i]))
      ur.updated = true
      ur.data.resolvedByName = 'Unknown'
      for (let u = 0; u < URs.users.objects.length; u++) {
        if (URs.users.objects[u].id === ur.data.resolvedBy) {
          ur.data.resolvedByName = URs.users.objects[u].userName
        }
      }
      for (let c = 0; c < ur.data.session.comments.length; c++) {
        const userID = ur.data.session.comments[c].userID
        let userName = 'Unknown'
        if (userID === WMEURMPT.me.getID()) {
          userName = WMEURMPT.me.getUsername()
          if (c === ur.data.session.comments.length - 1) {
            ur.lastVisitCommentsCount = ur.data.session.comments.length
          }
        }
        if (userID === -1) {
          userName = 'Reporter'
        } else {
          for (let u = 0; u < ur.data.session.users.objects.length; u++) {
            if (ur.data.session.users.objects[u].id === userID) {
              userName = ur.data.session.users.objects[u].userName
              break
            }
          }
        }
        ur.data.session.comments[c].userName = userName
      }
      ur.clean()
      ur.updateDistanceToMapCenter()
      if (!found) {
        ur.lastVisitCommentsCount = 0
        ur.alreadyVisited = false
        WMEURMPT.URList.push(ur)
        WMEURMPT.URMap = WMEURMPT.listToObject(WMEURMPT.URList)
      }
    }
  }

  WMEURMPT.updateMPList = function (MPs) {
    if (Object.prototype.hasOwnProperty.call(MPs, 'problems') === false) {
      return
    }
    WMEURMPT.logDebug('updatelist MPs:', MPs)
    for (let i = 0; i < MPs.problems.objects.length; i++) {
      WMEURMPT.logDebug('MP server Object:', MPs.problems.objects[i])
      let found = true
      let mp = WMEURMPT.getMPFromId(MPs.problems.objects[i].id)
      if (mp === null) {
        mp = new WMEURMPT.URT_MP(MPs.problems.objects[i].id, MPs.problems.objects[i].geometry.coordinates[0], MPs.problems.objects[i].geometry.coordinates[1])
        mp.alreadyVisited = false
        found = false
      }
      mp.updated = true
      mp.type = 'problem'
      mp.data = JSON.parse(JSON.stringify(MPs.problems.objects[i]))
      mp.data.resolvedByName = 'Unknown'
      for (let u = 0; u < MPs.users.objects.length; u++) {
        if (MPs.users.objects[u].id === mp.data.resolvedBy) {
          mp.data.resolvedByName = MPs.users.objects[u].userName
        }
      }
      mp.clean()
      mp.updateDistanceToMapCenter()
      if (!found) {
        WMEURMPT.MPList.push(mp)
        WMEURMPT.MPMap = WMEURMPT.listToObject(WMEURMPT.MPList)
      }
    }
    WMEURMPT.logDebug('MPList Updated:', WMEURMPT.MPList)
  }

  WMEURMPT.updateMCList = function (MCs) {
    if (Object.prototype.hasOwnProperty.call(MCs, 'mapComments') === false) {
      return
    }
    for (let i = 0; i < MCs.mapComments.objects.length; i++) {
      let found = true
      let mc = WMEURMPT.getMCFromId(MCs.mapComments.objects[i].id)
      if (mc == null) {
        if (MCs.mapComments.objects[i].geometry.type === 'Point') {
          mc = new WMEURMPT.URT_MC(MCs.mapComments.objects[i].id, MCs.mapComments.objects[i].geometry.coordinates[0], MCs.mapComments.objects[i].geometry.coordinates[1])
        } else {
          const olpolys = []
          MCs.mapComments.objects[i].geometry.coordinates.forEach(function (poly) {
            const olpts = poly.map(function (e) {
              return new OpenLayers.Geometry.Point(e[0], e[1])
            })
            const ollr = new OpenLayers.Geometry.LinearRing(olpts)
            const olp = new OpenLayers.Geometry.Polygon(ollr)
            olpolys.push(olp)
          })
          const olmultipoly = new OpenLayers.Geometry.MultiPolygon(olpolys)
          const centroid = olmultipoly.getCentroid()
          mc = new WMEURMPT.URT_MC(MCs.mapComments.objects[i].id, centroid.x, centroid.y)
        }
        found = false
      }
      mc.data = JSON.parse(JSON.stringify(MCs.mapComments.objects[i]))
      mc.updated = true
      mc.data.createdByName = 'Unknown'
      for (const u in MCs.users.objects) {
        if (MCs.users.objects[u].id === mc.data.createdBy) {
          mc.data.createdByName = MCs.users.objects[u].userName
          break
        }
      }
      mc.data.updatedByName = 'Unknown'
      for (const u in MCs.users.objects) {
        if (MCs.users.objects[u].id === mc.data.updatedBy) {
          mc.data.updatedByName = MCs.users.objects[u].userName
          break
        }
      }
      if (Object.prototype.hasOwnProperty.call(mc.data, 'conversation')) {
        mc.data.conversation.forEach(function (c, i) {
          if (c.userID === WMEURMPT.me.getID()) {
            c.userName = WMEURMPT.me.getUsername()
            if (i === mc.data.conversation.length - 1) {
              mc.lastVisitCommentsCount = mc.data.conversation.length
            }
          }
          for (const u in MCs.users.objects) {
            if (MCs.users.objects[u].id === c.userID) {
              c.userName = MCs.users.objects[u].userName
              break
            }
          }
        }, this)
      }
      mc.clean()
      mc.updateDistanceToMapCenter()
      if (!found) {
        mc.lastVisitCommentsCount = 0
        mc.alreadyVisited = false
        WMEURMPT.MCList.push(mc)
        WMEURMPT.MCMap = WMEURMPT.listToObject(WMEURMPT.MCList)
      }
    }
  }
  WMEURMPT.updatePURList = function (PURs) {
    if (Object.prototype.hasOwnProperty.call(PURs, 'venues') === false) {
      return
    }
    for (let i = 0; i < PURs.venues.objects.length; i++) {
      let found = true
      let pur = WMEURMPT.getPURFromId(PURs.venues.objects[i].id)
      if (pur == null) {
        if (PURs.venues.objects[i].geometry.type === 'Point') {
          pur = new WMEURMPT.URT_PUR(PURs.venues.objects[i].id, PURs.venues.objects[i].geometry.coordinates[0], PURs.venues.objects[i].geometry.coordinates[1])
        } else {
          const olpolys = []
          PURs.venues.objects[i].geometry.coordinates.forEach(function (poly) {
            const olpts = poly.map(function (e) {
              return new OpenLayers.Geometry.Point(e[0], e[1])
            })
            const ollr = new OpenLayers.Geometry.LinearRing(olpts)
            const olp = new OpenLayers.Geometry.Polygon(ollr)
            olpolys.push(olp)
          })
          const olmultipoly = new OpenLayers.Geometry.MultiPolygon(olpolys)
          const centroid = olmultipoly.getCentroid()
          pur = new WMEURMPT.URT_PUR(PURs.venues.objects[i].id, centroid.x, centroid.y)
        }
        found = false
      }
      pur.data = JSON.parse(JSON.stringify(PURs.venues.objects[i]))
      pur.updated = true
      if (pur.data.name === 'undefined') {
        pur.data.name = 'undefined'
      }
      pur.data.createdByName = 'Unknown'
      for (const u in PURs.users.objects) {
        if (PURs.users.objects[u].id === pur.data.createdBy) {
          pur.data.createdByName = PURs.users.objects[u].userName
          break
        }
      }
      pur.data.updatedByName = 'Unknown'
      for (const u in PURs.users.objects) {
        if (PURs.users.objects[u].id === pur.data.updatedBy) {
          pur.data.updatedByName = PURs.users.objects[u].userName
          break
        }
      }
      pur.data.dateAddedMin = 0
      pur.data.dateAddedMax = 0
      for (let n = 0; n < PURs.venues.objects[i].venueUpdateRequests.length; n++) {
        pur.data.venueUpdateRequests[n].createdByName = 'Unknown'
        for (const u in PURs.users.objects) {
          if (PURs.users.objects[u].id === pur.data.venueUpdateRequests[n].createdBy) {
            pur.data.venueUpdateRequests[n].createdByName = PURs.users.objects[u].userName
            break
          }
        }
        if (pur.data.venueUpdateRequests[n].dateAdded << pur.data.dateAddedMin) {
          pur.data.dateAddedMin = pur.data.venueUpdateRequests[n].dateAdded
        }
        if (pur.data.venueUpdateRequests[n].dateAdded >> pur.data.dateAddedMax) {
          pur.data.dateAddedMax = pur.data.venueUpdateRequests[n].dateAdded
        }
      }
      WMEURMPT.logDebug('updatePURList pur', pur)
      pur.clean()
      pur.updateDistanceToMapCenter()
      if (!found) {
        pur.alreadyVisited = false
        WMEURMPT.PURList.push(pur)
        WMEURMPT.PURMap = WMEURMPT.listToObject(WMEURMPT.PURList)
      }
    }
  }
  WMEURMPT.updateListsFromManualScan = function (areaFilter) {
    if (!WMEURMPT.scanUR && !WMEURMPT.scanMP && !WMEURMPT.scanMC && !WMEURMPT.scanPUR) {
      alert('You must check at least one scan in quick options')
      return
    }
    WMEURMPT.log('Setup tiles for manual scan: ', areaFilter)
    WMEURMPT.scanAreaBoundsList = []
    if (areaFilter.type === 'editableArea') {
      const userAreas = WMEURMPT.me.attributes.areas
      for (let i = 0; i < userAreas.length; i++) {
        userAreas[i].geometry.calculateBounds()
        const bounds = userAreas[i].geometry.bounds
        const lonlatFrom = OpenLayers.Layer.SphericalMercator.inverseMercator(bounds.left, bounds.bottom)
        const lonlatTo = OpenLayers.Layer.SphericalMercator.inverseMercator(bounds.right, bounds.top)
        for (let lat = lonlatFrom.lat; lat < lonlatTo.lat; lat += 0.5) {
          for (let lon = lonlatFrom.lon; lon < lonlatTo.lon; lon += 0.5) {
            WMEURMPT.logDebug('Scan editable area from: ' + lon + ' ' + lat + ' to: ' + (lon + 1) + ' ' + (lat + 1))
            const tileBounds = new OpenLayers.Bounds()
            tileBounds.extend(new OpenLayers.LonLat(lon.toFixed(6), lat.toFixed(6)))
            tileBounds.extend(new OpenLayers.LonLat((lon + 0.5).toFixed(6), (lat + 0.5).toFixed(6)))
            WMEURMPT.scanAreaBoundsList.push(tileBounds)
          }
        }
      }
    }
    if (areaFilter.type === 'driveArea') {
      for (let i = 0; i < WMEURMPT.driveArea.length; i++) {
        WMEURMPT.driveArea[i].calculateBounds()
        WMEURMPT.logDebug('WMEURMPT.driveArea', WMEURMPT.driveArea)
        const bounds = WMEURMPT.driveArea[i].bounds
        const lonlatFrom = OpenLayers.Layer.SphericalMercator.inverseMercator(bounds.left, bounds.bottom)
        const lonlatTo = OpenLayers.Layer.SphericalMercator.inverseMercator(bounds.right, bounds.top)
        for (let lat = lonlatFrom.lat; lat < lonlatTo.lat; lat += 0.5) {
          for (let lon = lonlatFrom.lon; lon < lonlatTo.lon; lon += 0.5) {
            WMEURMPT.logDebug('Scan drive area from: ' + lon + ' ' + lat + ' to: ' + (lon + 1) + ' ' + (lat + 1))
            const tileBounds = new OpenLayers.Bounds()
            tileBounds.extend(new OpenLayers.LonLat(lon.toFixed(6), lat.toFixed(6)))
            tileBounds.extend(new OpenLayers.LonLat((lon + 0.5).toFixed(6), (lat + 0.5).toFixed(6)))
            WMEURMPT.scanAreaBoundsList.push(tileBounds)
          }
        }
      }
    }
    if (areaFilter.type === 'managedArea') {
      for (let i = 0; i < WMEURMPT.managedAreas.length; i++) {
        WMEURMPT.managedAreas[i].calculateBounds()
        WMEURMPT.logDebug('WMEURMPT.managedAreas', WMEURMPT.managedAreas)
        const bounds = WMEURMPT.managedAreas[i].bounds
        const lonlatFrom = OpenLayers.Layer.SphericalMercator.inverseMercator(bounds.left, bounds.bottom)
        const lonlatTo = OpenLayers.Layer.SphericalMercator.inverseMercator(bounds.right, bounds.top)
        for (let lat = lonlatFrom.lat; lat < lonlatTo.lat; lat += 0.5) {
          for (let lon = lonlatFrom.lon; lon < lonlatTo.lon; lon += 0.5) {
            WMEURMPT.logDebug('Scan managed area from: ' + lon + ' ' + lat + ' to: ' + (lon + 1) + ' ' + (lat + 1))
            const tileBounds = new OpenLayers.Bounds()
            tileBounds.extend(new OpenLayers.LonLat(lon.toFixed(6), lat.toFixed(6)))
            tileBounds.extend(new OpenLayers.LonLat((lon + 0.5).toFixed(6), (lat + 0.5).toFixed(6)))
            WMEURMPT.scanAreaBoundsList.push(tileBounds)
          }
        }
      }
    }
    if (areaFilter.type === 'country') {
      let geometry = null
      for (let i = 0; i < WMEURMPT.areaList.country.length; i++) {
        if (WMEURMPT.areaList.country[i].name === areaFilter.name) {
          geometry = WMEURMPT.areaList.country[i].geometryOL.geometry.components
          break
        }
      }
      if (geometry === null) {
        return
      }
      for (let i = 0; i < geometry.length; i++) {
        const bounds = geometry[i].bounds
        const lonlatFrom = new OpenLayers.LonLat(bounds.left, bounds.bottom)
        const lonlatTo = new OpenLayers.LonLat(bounds.right, bounds.top)
        for (let lat = lonlatFrom.lat; lat < lonlatTo.lat; lat += 0.5) {
          for (let lon = lonlatFrom.lon; lon < lonlatTo.lon; lon += 0.5) {
            if (lon > 180) {
              lon -= 180
            }
            let lonStep = 0.5
            if (lon + lonStep > 180) {
              lonStep = 180 - lon
            }
            WMEURMPT.logDebug('Scan country from: ' + lon + ' ' + lat + ' to: ' + (lon + lonStep) + ' ' + (lat + 0.5))
            let tileBounds = new OpenLayers.Bounds()
            tileBounds.extend(new OpenLayers.LonLat(lon.toFixed(6), lat.toFixed(6)))
            tileBounds.extend(new OpenLayers.LonLat((lon + lonStep).toFixed(6), (lat + 0.5).toFixed(6)))
            WMEURMPT.scanAreaBoundsList.push(tileBounds)
            if (lonStep !== 0.5) {
              lonStep = 0.5 - lonStep
              WMEURMPT.logDebug('Scan country from: 0! ' + lat + ' to: ' + lonStep + ' ' + (lat + 0.5))
              tileBounds = new OpenLayers.Bounds()
              tileBounds.extend(new OpenLayers.LonLat(0, lat.toFixed(6)))
              tileBounds.extend(new OpenLayers.LonLat(lonStep.toFixed(6), (lat + 0.5).toFixed(6)))
              WMEURMPT.scanAreaBoundsList.push(tileBounds)
            }
          }
        }
      }
    }
    if (areaFilter.type === 'custom') {
      let geometry = null
      for (let i = 0; i < WMEURMPT.areaList.custom.length; i++) {
        if (WMEURMPT.areaList.custom[i].name === areaFilter.name) {
          geometry = WMEURMPT.areaList.custom[i].geometryOL.geometry.components
          break
        }
      }
      if (geometry === null) {
        WMEURMPT.log('Bad geometry for area: ', areaFilter)
        return
      }
      for (let i = 0; i < geometry.length; i++) {
        const bounds = geometry[i].bounds
        const lonlatFrom = new OpenLayers.LonLat(bounds.left, bounds.bottom)
        const lonlatTo = new OpenLayers.LonLat(bounds.right, bounds.top)
        for (let lat = lonlatFrom.lat; lat < lonlatTo.lat; lat += 0.5) {
          for (let lon = lonlatFrom.lon; lon < lonlatTo.lon; lon += 0.5) {
            WMEURMPT.logDebug('Scan custom from: ' + lon + ' ' + lat + ' to: ' + (lon + 1) + ' ' + (lat + 1))
            const tileBounds = new OpenLayers.Bounds()
            tileBounds.extend(new OpenLayers.LonLat(lon.toFixed(6), lat.toFixed(6)))
            tileBounds.extend(new OpenLayers.LonLat((lon + 0.5).toFixed(6), (lat + 0.5).toFixed(6)))
            WMEURMPT.scanAreaBoundsList.push(tileBounds)
          }
        }
      }
    }
    WMEURMPT.scanAreaBoundsCount = WMEURMPT.scanAreaBoundsList.length
    for (let i = 0; i < WMEURMPT.URList.length; i++) {
      WMEURMPT.URList[i].updated = false
    }
    for (let i = 0; i < WMEURMPT.MPList.length; i++) {
      WMEURMPT.MPList[i].updated = false
    }
    for (let i = 0; i < WMEURMPT.MCList.length; i++) {
      WMEURMPT.MCList[i].updated = false
    }
    for (let i = 0; i < WMEURMPT.PURList.length; i++) {
      WMEURMPT.PURList[i].updated = false
    }
    WMEURMPT.log('Starting scan...')
    WMEURMPT.log('Tile count: ' + WMEURMPT.scanAreaBoundsList.length)
    const pb = new WMEURMPT.ProgressBar(WMEURMPT.getId('urt-progressBar'))
    pb.update(0)
    pb.show()
    WMEURMPT.showPBInfo(true)
    WMEURMPT.wasAutoScan = WMEURMPT.isAutoScan
    window.setTimeout(WMEURMPT.getFunctionWithArgs(WMEURMPT.updateListsFromManualScanNextStep, [areaFilter]), 0)
  }

  WMEURMPT.updateListsFromManualScanNextStep = function (areaFilter, seconds, retries) {
    const pb = new WMEURMPT.ProgressBar(WMEURMPT.getId('urt-progressBar'))
    if (typeof seconds !== 'undefined' && seconds != null && seconds > 0) {
      seconds--
      WMEURMPT.info("Error: can't download data from waze server.<br>Retry in " + seconds + 's.')
      window.setTimeout(WMEURMPT.getFunctionWithArgs(WMEURMPT.updateListsFromManualScanNextStep, [areaFilter, seconds, retries]), 1000)
      return
    }
    if (typeof retries !== 'undefined' && retries != null && retries > 0) {
      retries--
      WMEURMPT.log("Error: can't download data from waze server.<br>Retry in " + seconds + 's.')
      window.setTimeout(WMEURMPT.getFunctionWithArgs(WMEURMPT.updateListsFromManualScanNextStep, [areaFilter, WMEURMPT.wazeServerWaitingTimeToRetry, retries]), 1000)
      return
    }

    let tileBounds = WMEURMPT.scanAreaBoundsList[0]

    if (typeof retries !== 'undefined' && retries !== null && retries === 0 && typeof seconds !== 'undefined' && seconds !== null && seconds === 0) {
      WMEURMPT.scanAreaBoundsList.shift()
      if (tileBounds.right - tileBounds.left > 0.02 && tileBounds.top - tileBounds.bottom > 0.02) {
        WMEURMPT.log('Error from waze server. Try a split...')
        let newTileBounds = new OpenLayers.Bounds()
        newTileBounds.extend(new OpenLayers.LonLat(tileBounds.left, tileBounds.bottom))
        newTileBounds.extend(new OpenLayers.LonLat((tileBounds.left + tileBounds.right) / 2.0, (tileBounds.bottom + tileBounds.top) / 2.0))
        WMEURMPT.scanAreaBoundsList.unshift(newTileBounds)
        newTileBounds = new OpenLayers.Bounds()
        newTileBounds.extend(new OpenLayers.LonLat((tileBounds.left + tileBounds.right) / 2.0, tileBounds.bottom))
        newTileBounds.extend(new OpenLayers.LonLat(tileBounds.right, (tileBounds.bottom + tileBounds.top) / 2.0))
        WMEURMPT.scanAreaBoundsList.unshift(newTileBounds)
        newTileBounds = new OpenLayers.Bounds()
        newTileBounds.extend(new OpenLayers.LonLat(tileBounds.left, (tileBounds.bottom + tileBounds.top) / 2.0))
        newTileBounds.extend(new OpenLayers.LonLat((tileBounds.left + tileBounds.right) / 2.0, tileBounds.top))
        WMEURMPT.scanAreaBoundsList.unshift(newTileBounds)
        newTileBounds = new OpenLayers.Bounds()
        newTileBounds.extend(new OpenLayers.LonLat((tileBounds.left + tileBounds.right) / 2.0, (tileBounds.bottom + tileBounds.top) / 2.0))
        newTileBounds.extend(new OpenLayers.LonLat(tileBounds.right, tileBounds.top))
        WMEURMPT.scanAreaBoundsList.unshift(newTileBounds)
        WMEURMPT.scanAreaBoundsCount += 4
      } else {
        WMEURMPT.log('Abort this area: (' + tileBounds.left + ' , ' + tileBounds.bottom + ') -> (' + tileBounds.right + ' , ' + tileBounds.top + ')')
      }
    }
    if (WMEURMPT.scanAreaBoundsList.length === 0) {
      WMEURMPT.log('Found after process: ' + (WMEURMPT.URList.length >> 0 ? WMEURMPT.URList.length + ' URs; ' : '') + (WMEURMPT.MPList.length >> 0 ? WMEURMPT.MPList.length + ' MPs; ' : '') + (WMEURMPT.MCList.length >> 0 ? WMEURMPT.MCList.length + ' MCs; ' : '') + (WMEURMPT.PURList.length >> 0 ? WMEURMPT.PURList.length + ' PURs' : ''))
      WMEURMPT.log('Scan ended')
      WMEURMPT.showPBInfo(false)
      WMEURMPT.info()
      pb.hide()
      WMEURMPT.refreshStats('', '')
      WMEURMPT.updateIHMFromURList()
      WMEURMPT.updateIHMFromMPList()
      WMEURMPT.updateIHMFromMCList()
      WMEURMPT.updateIHMFromPURList()
      WMEURMPT.saveURMPLists()
      WMEURMPT.isAutoScan = WMEURMPT.wasAutoScan
      return
    }

    tileBounds = WMEURMPT.scanAreaBoundsList[0]
    const progression = Math.floor((1 - WMEURMPT.scanAreaBoundsList.length / WMEURMPT.scanAreaBoundsCount) * 100)
    const MPs = WMEURMPT.getMPs(tileBounds, areaFilter)

    WMEURMPT.scanAreaBoundsList.shift()
    if (MPs != null) {
      if (Object.prototype.hasOwnProperty.call(MPs, 'error') && MPs.error === 1) {
        WMEURMPT.log('Found ' + MPs.logMessage.length + ' ' + MPs.logMessage.obj + '. This is a waze server limit. Enqueuing sub tile...')
        let newTileBounds = new OpenLayers.Bounds()
        newTileBounds.extend(new OpenLayers.LonLat(tileBounds.left, tileBounds.bottom))
        newTileBounds.extend(new OpenLayers.LonLat((tileBounds.left + tileBounds.right) / 2.0, (tileBounds.bottom + tileBounds.top) / 2.0))
        WMEURMPT.scanAreaBoundsList.unshift(newTileBounds)
        newTileBounds = new OpenLayers.Bounds()
        newTileBounds.extend(new OpenLayers.LonLat((tileBounds.left + tileBounds.right) / 2.0, tileBounds.bottom))
        newTileBounds.extend(new OpenLayers.LonLat(tileBounds.right, (tileBounds.bottom + tileBounds.top) / 2.0))
        WMEURMPT.scanAreaBoundsList.unshift(newTileBounds)
        newTileBounds = new OpenLayers.Bounds()
        newTileBounds.extend(new OpenLayers.LonLat(tileBounds.left, (tileBounds.bottom + tileBounds.top) / 2.0))
        newTileBounds.extend(new OpenLayers.LonLat((tileBounds.left + tileBounds.right) / 2.0, tileBounds.top))
        WMEURMPT.scanAreaBoundsList.unshift(newTileBounds)
        newTileBounds = new OpenLayers.Bounds()
        newTileBounds.extend(new OpenLayers.LonLat((tileBounds.left + tileBounds.right) / 2.0, (tileBounds.bottom + tileBounds.top) / 2.0))
        newTileBounds.extend(new OpenLayers.LonLat(tileBounds.right, tileBounds.top))
        WMEURMPT.scanAreaBoundsList.unshift(newTileBounds)
        WMEURMPT.scanAreaBoundsCount += 4
      } else {
        WMEURMPT.log('Found: ' + (Object.prototype.hasOwnProperty.call(MPs, 'mapUpdateRequests') ? MPs.mapUpdateRequests.objects.length + ' URs; ' : '') + (Object.prototype.hasOwnProperty.call(MPs, 'problems') ? MPs.problems.objects.length + ' MPs; ' : '') + (Object.prototype.hasOwnProperty.call(MPs, 'mapComments') ? MPs.mapComments.objects.length + ' MCs; ' : '') + (Object.prototype.hasOwnProperty.call(MPs, 'venues') ? MPs.venues.objects.length + ' PURs' : ''))
        WMEURMPT.updateURList(MPs)
        WMEURMPT.updateMPList(MPs)
        WMEURMPT.updateMCList(MPs)
        WMEURMPT.updatePURList(MPs)
        WMEURMPT.removeOldURMP(MPs.area, MPs.filterType, MPs.tile)
      }
    }
    pb.update(progression)
    WMEURMPT.info("Please, don't touch anything during this scan.")
    window.setTimeout(WMEURMPT.getFunctionWithArgs(WMEURMPT.updateListsFromManualScanNextStep, [areaFilter]), 0)
  }
  WMEURMPT.removeOldURMP = function (filterArea, type, tileBounds) {
    let i = 0
    const now = new Date()
    if (WMEURMPT.scanUR) {
      while (i < WMEURMPT.URList.length) {
        if (Object.prototype.hasOwnProperty.call(WMEURMPT.URList[i].data, 'session') === false) {
          WMEURMPT.log('pas bon ca: ', WMEURMPT.URList[i])
        }
        let xy = new OpenLayers.Geometry.Point(WMEURMPT.URList[i].lonlat.lon, WMEURMPT.URList[i].lonlat.lat)
        if (type === 'editableArea' || type === 'driveArea' || type === 'managedArea') {
          xy = OpenLayers.Layer.SphericalMercator.inverseMercator(xy.x, xy.y)
        }
        if (xy.x < tileBounds.left || xy.x > tileBounds.right || xy.y < tileBounds.bottom || xy.y > tileBounds.top) {
          i++
          continue
        }
        let inside = false
        for (let a = 0; a < filterArea.length; a++) {
          if (Object.prototype.hasOwnProperty.call(filterArea[a], 'bintreeContainsPoint') === false) {
            if (xy.x >= filterArea[a].bounds.left && xy.x <= filterArea[a].bounds.right && xy.y >= filterArea[a].bounds.bottom && xy.y <= filterArea[a].bounds.top && filterArea[a].containsPoint(xy)) {
              inside = true
              break
            }
          } else {
            if (filterArea[a].bintreeContainsPoint(xy)) {
              inside = true
              break
            }
          }
        }
        if (!inside) {
          i++
          continue
        }
        if ((WMEURMPT.URList[i].data.open === true && WMEURMPT.URList[i].updated === false) || (WMEURMPT.URList[i].data.open === false && Math.floor((now.getTime() - WMEURMPT.URList[i].data.resolvedOn) / 86400000) > 60)) {
          WMEURMPT.log('removing old UR ' + WMEURMPT.URList[i].id)
          WMEURMPT.URList.splice(i, 1)
          WMEURMPT.URMap = WMEURMPT.listToObject(WMEURMPT.URList)
        } else {
          i++
        }
      }
    }
    i = 0
    if (WMEURMPT.scanMP) {
      while (i < WMEURMPT.MPList.length) {
        let xy = new OpenLayers.Geometry.Point(WMEURMPT.MPList[i].lonlat.lon, WMEURMPT.MPList[i].lonlat.lat)
        if (type === 'editableArea' || type === 'driveArea' || type === 'managedArea') {
          xy = OpenLayers.Layer.SphericalMercator.inverseMercator(xy.x, xy.y)
        }
        if (xy.x < tileBounds.left || xy.x > tileBounds.right || xy.y < tileBounds.bottom || xy.y > tileBounds.top) {
          i++
          continue
        }
        let inside = false
        for (let a = 0; a < filterArea.length; a++) {
          if (Object.prototype.hasOwnProperty.call(filterArea[a], 'bintreeContainsPoint') === false) {
            if (xy.x >= filterArea[a].bounds.left && xy.x <= filterArea[a].bounds.right && xy.y >= filterArea[a].bounds.bottom && xy.y <= filterArea[a].bounds.top && filterArea[a].containsPoint(xy)) {
              inside = true
              break
            }
          } else {
            if (filterArea[a].bintreeContainsPoint(xy)) {
              inside = true
              break
            }
          }
        }
        if (!inside) {
          i++
          continue
        }
        if ((WMEURMPT.MPList[i].data.open === true && WMEURMPT.MPList[i].updated === false) || (WMEURMPT.MPList[i].data.open === false && Math.floor((now.getTime() - WMEURMPT.MPList[i].data.resolvedOn) / 86400000) > 60)) {
          WMEURMPT.log('removing old MP ' + WMEURMPT.MPList[i].id)
          WMEURMPT.MPList.splice(i, 1)
          WMEURMPT.MPMap = WMEURMPT.listToObject(WMEURMPT.MPList)
        } else {
          i++
        }
      }
    }
    i = 0
    if (WMEURMPT.scanMC) {
      while (i < WMEURMPT.MCList.length) {
        let xy = new OpenLayers.Geometry.Point(WMEURMPT.MCList[i].lonlat.lon, WMEURMPT.MCList[i].lonlat.lat)
        if (type === 'editableArea' || type === 'driveArea' || type === 'managedArea') {
          xy = OpenLayers.Layer.SphericalMercator.inverseMercator(xy.x, xy.y)
        }
        if (xy.x < tileBounds.left || xy.x > tileBounds.right || xy.y < tileBounds.bottom || xy.y > tileBounds.top) {
          i++
          continue
        }
        let inside = false
        for (let a = 0; a < filterArea.length; a++) {
          if (Object.prototype.hasOwnProperty.call(filterArea[a], 'bintreeContainsPoint') === false) {
            if (xy.x >= filterArea[a].bounds.left && xy.x <= filterArea[a].bounds.right && xy.y >= filterArea[a].bounds.bottom && xy.y <= filterArea[a].bounds.top && filterArea[a].containsPoint(xy)) {
              inside = true
              break
            }
          } else {
            if (filterArea[a].bintreeContainsPoint(xy)) {
              inside = true
              break
            }
          }
        }
        if (!inside) {
          i++
          continue
        }
        if (WMEURMPT.MCList[i].updated === false) {
          WMEURMPT.log('removing old MC ' + WMEURMPT.MCList[i].id)
          WMEURMPT.MCList.splice(i, 1)
          WMEURMPT.MCMap = WMEURMPT.listToObject(WMEURMPT.MCList)
        } else {
          i++
        }
      }
    }
    i = 0
    if (WMEURMPT.scanPUR) {
      while (i < WMEURMPT.PURList.length) {
        let xy = new OpenLayers.Geometry.Point(WMEURMPT.PURList[i].lonlat.lon, WMEURMPT.PURList[i].lonlat.lat)
        if (type === 'editableArea' || type === 'driveArea' || type === 'managedArea') {
          xy = OpenLayers.Layer.SphericalMercator.inverseMercator(xy.x, xy.y)
        }
        if (xy.x < tileBounds.left || xy.x > tileBounds.right || xy.y < tileBounds.bottom || xy.y > tileBounds.top) {
          i++
          continue
        }
        let inside = false
        for (let a = 0; a < filterArea.length; a++) {
          if (Object.prototype.hasOwnProperty.call(filterArea[a], 'bintreeContainsPoint') === false) {
            if (xy.x >= filterArea[a].bounds.left && xy.x <= filterArea[a].bounds.right && xy.y >= filterArea[a].bounds.bottom && xy.y <= filterArea[a].bounds.top && filterArea[a].containsPoint(xy)) {
              inside = true
              break
            }
          } else {
            if (filterArea[a].bintreeContainsPoint(xy)) {
              inside = true
              break
            }
          }
        }
        if (!inside) {
          i++
          continue
        }
        if (WMEURMPT.PURList[i].updated === false) {
          WMEURMPT.log('removing old PUR ' + WMEURMPT.PURList[i].id)
          WMEURMPT.PURList.splice(i, 1)
          WMEURMPT.PURMap = WMEURMPT.listToObject(WMEURMPT.PURList)
        } else {
          i++
        }
      }
    }
  }

  WMEURMPT.URT_UR = function (id, lon, lat) {
    this.id = id
    this.lonlat = new OpenLayers.LonLat(lon, lat)
    this.blackListed = false
    this.alreadyVisited = false
    this.lastVisitCommentsCount = 0
    this.refreshFromServer = refreshFromServer
    this.refreshFromWMEData = refreshFromWMEData
    this.distanceToMapCenter = 0
    this.clean = clean
    this.updateDistanceToMapCenter = updateDistanceToMapCenter
    function clean () {
      if (Object.prototype.hasOwnProperty.call(this.data, 'bounds') === true) {
        delete this.data.bounds
      }
      if (Object.prototype.hasOwnProperty.call(this.data, 'geometry') === true) {
        delete this.data.geometry
      }
      if (Object.prototype.hasOwnProperty.call(this.data, 'session') === true) {
        if (Object.prototype.hasOwnProperty.call(this.data.session, 'driveGeometry') === true) {
          delete this.data.session.driveGeometry
        }
        if (Object.prototype.hasOwnProperty.call(this.data.session, 'routeGeometry') === true) {
          delete this.data.session.routeGeometry
        }
        if (Object.prototype.hasOwnProperty.call(this.data.session, 'routeInstructions') === true) {
          delete this.data.session.routeInstructions
        }
        if (Object.prototype.hasOwnProperty.call(this.data.session, 'users') === true) {
          delete this.data.session.users
        }
      }
    }
    function updateDistanceToMapCenter () {
      if (!WMEURMPT.isComputeDistances) {
        return
      }
      if (!WMEURMPT.mapCenterLonLat) {
        WMEURMPT.mapCenterLonLat = OpenLayers.Layer.SphericalMercator.inverseMercator(WMEURMPT.wazeMap.olMap.center.lon, WMEURMPT.wazeMap.olMap.center.lat)
      }
      const p1 = new OpenLayers.Geometry.Point(WMEURMPT.mapCenterLonLat.lon, WMEURMPT.mapCenterLonLat.lat)
      const p2 = new OpenLayers.Geometry.Point(this.lonlat.lon, this.lonlat.lat)
      const line = new OpenLayers.Geometry.LineString([p1, p2])
      this.distanceToMapCenter = line.getGeodesicLength(new OpenLayers.Projection('EPSG:4326'))
    }
    function refreshFromWMEData (forceSession) {
      const theUR = WMEURMPT.wazeModel.mapUpdateRequests.objects[this.id]
      WMEURMPT.logDebug('refreshFromWME UR:', theUR)
      if (theUR == null) {
        return false
      }
      WMEURMPT.logDebug('refreshFromWME session:', WMEURMPT.wazeModel.updateRequestSessions.objects[this.id])
      this.data = {}
      this.data.description = theUR.attributes.description
      this.data.driveDate = theUR.attributes.driveDate
      this.data.hasComments = theUR.attributes.hasComments
      this.data.open = theUR.attributes.open
      this.data.resolution = theUR.attributes.resolution
      this.data.resolvedBy = theUR.attributes.resolvedBy
      this.data.resolvedOn = theUR.attributes.resolvedOn
      this.data.type = theUR.attributes.type
      this.data.updatedBy = theUR.attributes.updatedBy
      this.data.updatedOn = theUR.attributes.updatedOn
      this.data.resolvedByName = 'Unknown'
      for (const u in theUR.model.users.objects) {
        if (theUR.model.users.objects[u].id === this.data.resolvedBy) {
          this.data.resolvedByName = theUR.model.users.objects[u].userName
          break
        }
      }
      let needToUpdateCommentsUserNames = true
      if (!forceSession) {
        if (WMEURMPT.wazeModel.updateRequestSessions.objects[this.id] != null) {
          this.data.session = {}
          this.data.session.comments = JSON.parse(JSON.stringify(WMEURMPT.wazeModel.updateRequestSessions.objects[this.id].attributes.comments))
          this.data.session.isFollowing = WMEURMPT.wazeModel.updateRequestSessions.objects[this.id].attributes.isFollowing
        } else {
          this.data.session = {}
          this.data.session.comments = []
          this.data.session.isFollowing = false
        }
      } else {
        const url = 'https://' + document.location.host + WMEURMPT.wazeConfigApiUpdateRequestSessions + '?ids=' + this.id
        let xhr3Object = null
        if (XMLHttpRequest) {
          xhr3Object = new XMLHttpRequest()
        } else if (ActiveXObject) {
          xhr3Object = new ActiveXObject('Microsoft.XMLHTTP')
        }
        let URcomments = null
        xhr3Object.open('GET', url, false)
        xhr3Object.ontimeout = function () {
          URcomments = null
        }
        xhr3Object.onerror = function (e) {
          WMEURMPT.log('Error while getting UR comments from Waze server.', e)
          URcomments = null
        }
        xhr3Object.onreadystatechange = function () {
          if (xhr3Object.readyState === 4) {
            const r = xhr3Object.responseText
            try {
              URcomments = JSON.parse(r)
            } catch (e) {
              WMEURMPT.log("Error: can't read server response: ", e)
              WMEURMPT.log('Response from server: ', r)
              WMEURMPT.log('Query: ', url)
              URcomments = null
            }
          } else {
            WMEURMPT.log('Error while getting UR comments from Waze server.', xhr3Object)
            URcomments = null
          }
        }
        xhr3Object.send(null)
        WMEURMPT.logDebug('UR comments: ', URcomments)
        if (URcomments != null) {
          let found = false
          for (let j = 0; j < URcomments.updateRequestSessions.objects.length; j++) {
            const urId = URcomments.updateRequestSessions.objects[j].id
            if (urId === this.id) {
              this.data.session = URcomments.updateRequestSessions.objects[j]
              this.data.session.users = URcomments.users
              for (let c = 0; c < this.data.session.comments.length; c++) {
                const userID = this.data.session.comments[c].userID
                let userName = 'Unknown'
                if (userID === WMEURMPT.me.getID()) {
                  userName = WMEURMPT.me.getUsername()
                  if (c === this.data.session.comments.length - 1) {
                    this.lastVisitCommentsCount = this.data.session.comments.length
                  }
                }
                if (userID === -1) {
                  userName = 'Reporter'
                } else {
                  for (let u = 0; u < this.data.session.users.objects.length; u++) {
                    if (this.data.session.users.objects[u].id === userID) {
                      userName = this.data.session.users.objects[u].userName
                      break
                    }
                  }
                }
                this.data.session.comments[c].userName = userName
              }
              found = true
              needToUpdateCommentsUserNames = false
            }
          }
          if (!found) {
            this.data.session = {}
            this.data.session.comments = []
            this.data.session.isFollowing = false
          }
        } else {
          this.data.session = {}
          this.data.session.comments = []
          this.data.session.isFollowing = false
        }
      }
      if (needToUpdateCommentsUserNames) {
        for (let c = 0; c < this.data.session.comments.length; c++) {
          const userID = this.data.session.comments[c].userID
          let userName = 'Unknown'
          if (userID === WMEURMPT.me.getID()) {
            userName = WMEURMPT.me.getUsername()
            if (c === this.data.session.comments.length - 1) {
              this.lastVisitCommentsCount = this.data.session.comments.length
            }
          }
          if (userID === -1) {
            userName = 'Reporter'
          } else {
            for (const u in WMEURMPT.wazeModel.updateRequestSessions.objects[this.id].model.users.objects) {
              if (WMEURMPT.wazeModel.updateRequestSessions.objects[this.id].model.users.objects[u].id === userID) {
                userName = WMEURMPT.wazeModel.updateRequestSessions.objects[this.id].model.users.objects[u].userName
                break
              }
            }
          }
          this.data.session.comments[c].userName = userName
        }
      }
      this.clean()
      this.updateDistanceToMapCenter()
      WMEURMPT.updateIHMFromURList()
      return true
    }
    function refreshFromServer () {
      let haveChanged = false
      WMEURMPT.log('refresh from server ' + this.id)
      const URs = WMEURMPT.getUR(this.lonlat.lon, this.lonlat.lat, this.id)
      if (URs != null) {
        WMEURMPT.log('refresh from server ' + this.id + ';', URs)
        if (typeof URs.mapUpdateRequests !== 'undefined') {
          for (let i = 0; i < URs.mapUpdateRequests.objects.length; i++) {
            if (URs.mapUpdateRequests.objects[i].id === this.id) {
              if (this.data.updatedOn !== URs.mapUpdateRequests.objects[i].updatedOn) {
                haveChanged = true
              }
              WMEURMPT.log('refresh from server ' + this.id + ';', URs.mapUpdateRequests.objects[i])
              this.data = URs.mapUpdateRequests.objects[i]
              this.data.resolvedByName = 'Unknown'
              for (let u = 0; u < URs.users.objects.length; u++) {
                if (URs.users.objects[u].id === this.data.resolvedBy) {
                  this.data.resolvedByName = URs.users.objects[u].userName
                }
              }
              for (let c = 0; c < this.data.session.comments.length; c++) {
                const userID = this.data.session.comments[c].userID
                let userName = 'Unknown'
                if (userID === -1) {
                  userName = 'Reporter'
                } else {
                  for (let u = 0; u < URs.users.objects.length; u++) {
                    if (URs.users.objects[u].userID === userID) {
                      userName = URs.users.objects[u].userName
                      break
                    }
                  }
                  for (let u = 0; u < URs.mapUpdateRequests.objects[i].session.users.objects.length; u++) {
                    if (URs.mapUpdateRequests.objects[i].session.users.objects[u].id === userID) {
                      userName = URs.mapUpdateRequests.objects[i].session.users.objects[u].userName
                      break
                    }
                  }
                  if (userID === WMEURMPT.loginManager.user.getID()) {
                    userName = WMEURMPT.loginManager.user.getUsername()
                  }
                }
                this.data.session.comments[c].userName = userName
              }
            }
          }
          return haveChanged
        }
      }
      return null
    }
  }

  WMEURMPT.getUR = function (lon, lat, id) {
    const bounds = new OpenLayers.Bounds(lon - 0.01, lat - 0.01, lon + 0.01, lat + 0.01)
    const URs = WMEURMPT.getMPs(bounds)
    if (URs == null) {
      return null
    }
    if (id != null) {
      while (URs.mapUpdateRequests.objects.length >= 2) {
        for (let i = 0; i < URs.mapUpdateRequests.objects.length; i++) {
          if (URs.mapUpdateRequests.objects[i].id !== id) {
            URs.mapUpdateRequests.objects.splice(i, 1)
            break
          }
        }
      }
      if (URs.mapUpdateRequests.objects.length === 0) {
        return null
      }
      if (URs.mapUpdateRequests.objects[0].id !== id) {
        return null
      }
    }
    return URs
  }

  WMEURMPT.URT_MP = function (id, lon, lat) {
    this.id = id
    this.lonlat = new OpenLayers.LonLat(lon, lat)
    this.blackListed = false
    this.alreadyVisited = false
    this.distanceToMapCenter = 0
    this.type = 'problem'
    this.refreshFromServer = refreshFromServer
    this.refreshFromWMEData = refreshFromWMEData
    this.clean = clean
    this.updateDistanceToMapCenter = updateDistanceToMapCenter
    function clean () {
      delete this.data.bounds
      delete this.data.geometry
    }
    function updateDistanceToMapCenter () {
      if (!WMEURMPT.isComputeDistances) {
        return
      }
      if (!WMEURMPT.mapCenterLonLat) {
        WMEURMPT.mapCenterLonLat = OpenLayers.Layer.SphericalMercator.inverseMercator(WMEURMPT.wazeMap.olMap.center.lon, WMEURMPT.wazeMap.olMap.center.lat)
      }
      const p1 = new OpenLayers.Geometry.Point(WMEURMPT.mapCenterLonLat.lon, WMEURMPT.mapCenterLonLat.lat)
      const p2 = new OpenLayers.Geometry.Point(this.lonlat.lon, this.lonlat.lat)
      const line = new OpenLayers.Geometry.LineString([p1, p2])
      this.distanceToMapCenter = line.getGeodesicLength(new OpenLayers.Projection('EPSG:4326'))
    }
    function refreshFromWMEData () {
      WMEURMPT.logDebug('Refresh MP: ', WMEURMPT.wazeModel.mapProblems.additionalInfo)
      let theMP = null
      if (Object.prototype.hasOwnProperty.call(WMEURMPT.wazeModel.mapProblems.objects, this.id)) {
        theMP = WMEURMPT.wazeModel.mapProblems.objects[this.id]
      }
      if (theMP == null) {
        return false
      }
      this.data = {}
      this.data.priority = theMP.attributes.priority
      this.data.subType = theMP.attributes.subType
      this.data.open = theMP.attributes.open
      this.data.resolution = theMP.attributes.resolution
      this.data.resolvedBy = theMP.attributes.resolvedBy
      this.data.resolvedOn = theMP.attributes.resolvedOn
      this.data.weight = theMP.attributes.weight
      this.data.startTime = theMP.attributes.startTime
      this.data.resolvedByName = 'Unknown'
      for (const u in theMP.model.users.objects) {
        if (theMP.model.users.objects[u].id === this.data.resolvedBy) {
          this.data.resolvedByName = theMP.model.users.objects[u].userName
          break
        }
      }
      this.clean()
      this.updateDistanceToMapCenter()
      return true
    }
    function refreshFromServer () {
      let haveChanged = false
      const MPs = WMEURMPT.getMP(this.lonlat.lon, this.lonlat.lat, this.id)
      if (MPs != null) {
        if (typeof MPs.problems !== 'undefined') {
          for (let i = 0; i < MPs.problems.objects.length; i++) {
            if (MPs.problems.objects[i].id === this.id) {
              if (this.data.updatedOn !== MPs.problems.objects[i].updatedOn) {
                haveChanged = true
              }
              this.data = MPs.problems.objects[i]
              return haveChanged
            }
          }
        }
      }
      return null
    }
  }

  WMEURMPT.getMP = function (lon, lat, id) {
    const bounds = new OpenLayers.Bounds(lon - 0.01, lat - 0.01, lon + 0.01, lat + 0.01)
    const MPs = WMEURMPT.getMPs(bounds)
    if (MPs == null) {
      return null
    }
    if (id != null) {
      while (MPs.problems.objects.length >= 2) {
        for (let i = 0; i < MPs.problems.objects.length; i++) {
          if (MPs.problems.objects[i].id !== id) {
            MPs.problems.objects.splice(i, 1)
            break
          }
        }
      }
      if (MPs.problems.objects.length !== 0 && MPs.problems.objects[0].id !== id) {
        return null
      }
    }
    if (MPs.problems.objects.length === 0) {
      return null
    }
    return MPs
  }

  WMEURMPT.URT_MC = function (id, lon, lat) {
    this.id = id
    this.lonlat = new OpenLayers.LonLat(lon, lat)
    this.blackListed = false
    this.alreadyVisited = false
    this.lastVisitCommentsCount = 0
    this.refreshFromServer = refreshFromServer
    this.refreshFromWMEData = refreshFromWMEData
    this.distanceToMapCenter = 0
    this.clean = clean
    this.updateDistanceToMapCenter = updateDistanceToMapCenter
    function clean () {
      if (Object.prototype.hasOwnProperty.call(this.data, 'bounds') === true) {
        delete this.data.bounds
      }
      if (Object.prototype.hasOwnProperty.call(this.data, 'geometry') === true) {
        delete this.data.geometry
      }
    }
    function updateDistanceToMapCenter () {
      if (!WMEURMPT.isComputeDistances) {
        return
      }
      if (!WMEURMPT.mapCenterLonLat) {
        WMEURMPT.mapCenterLonLat = OpenLayers.Layer.SphericalMercator.inverseMercator(WMEURMPT.wazeMap.olMap.center.lon, WMEURMPT.wazeMap.olMap.center.lat)
      }
      const p1 = new OpenLayers.Geometry.Point(WMEURMPT.mapCenterLonLat.lon, WMEURMPT.mapCenterLonLat.lat)
      const p2 = new OpenLayers.Geometry.Point(this.lonlat.lon, this.lonlat.lat)
      const line = new OpenLayers.Geometry.LineString([p1, p2])
      this.distanceToMapCenter = line.getGeodesicLength(new OpenLayers.Projection('EPSG:4326'))
    }
    function refreshFromWMEData (forceSession) {
      const theMC = WMEURMPT.wazeModel.mapComments.objects[this.id]
      WMEURMPT.logDebug('refreshFromWME MC:', theMC)
      if (theMC == null) {
        return false
      }
      this.data = {};
      ['body', 'createdBy', 'createdOn', 'endDate', 'isFollowing', 'subject', 'updatedBy', 'updatedOn'].forEach(function (p) {
        this.data[p] = theMC.attributes[p]
      }, this)
      this.data.createdByName = 'Unknown'
      for (const u in W.model.users.objects) {
        if (W.model.users.objects[u].id === this.data.createdBy) {
          this.data.createdByName = W.model.users.objects[u].userName
          break
        }
      }
      this.data.updatedByName = 'Unknown'
      for (const u in W.model.users.objects) {
        if (W.model.users.objects[u].id === this.data.updatedBy) {
          this.data.updatedByName = W.model.users.objects[u].userName
          break
        }
      }
      this.data.conversation = []
      if (Object.prototype.hasOwnProperty.call(theMC, 'conversation')) {
        theMC.attributes.conversation.forEach(function (c, i) {
          if (c.userID === WMEURMPT.me.getID()) {
            c.userName = WMEURMPT.me.getUsername()
            if (i === theMC.attributes.conversation.length - 1) {
              this.lastVisitCommentsCount = theMC.attributes.conversation.length
            }
          }
          this.data.conversation.push(JSON.parse(JSON.stringify(c)))
          this.data.conversation[this.data.conversation.length - 1].userName = W.model.users.objects[c.userID].userName
        }, this)
      }
      if (Object.prototype.hasOwnProperty.call(theMC, 'state') && theMC.state === 'DELETE') {
        WMEURMPT.MCList.splice(WMEURMPT.MCMap[this.id], 1)
        WMEURMPT.MCMap = WMEURMPT.listToObject(WMEURMPT.MCList)
        this.clean()
        WMEURMPT.updateIHMFromMCList()
        return
      }
      this.clean()
      this.updateDistanceToMapCenter()
      WMEURMPT.updateIHMFromMCList()
      return true
    }

    function refreshFromServer () {
      let haveChanged = false
      WMEURMPT.log('refresh from server MC.id: ' + this.id)
      const MCs = WMEURMPT.getMC(this.lonlat.lon, this.lonlat.lat, this.id)
      if (MCs != null) {
        WMEURMPT.log('MC refresh from server MC.id: ' + this.id + ';', MCs)
        if (typeof MCs.mapComments !== 'undefined') {
          for (let i = 0; i < MCs.mapComments.objects.length; i++) {
            if (MCs.mapComments.objects[i].id === this.id) {
              if (this.data.updatedOn !== MCs.mapComments.objects[i].updatedOn) {
                haveChanged = true
              }
              WMEURMPT.log('refresh from server ' + this.id + ';', MCs.mapComments.objects[i])
              this.data = MCs.mapComments.objects[i]
              this.data.createdByName = 'Unknown'
              for (const u in MCs.users.objects) {
                if (MCs.users.objects[u].id === this.data.createdBy) {
                  this.data.createdByName = MCs.users.objects[u].userName
                  break
                }
              }
              this.data.updatedByName = 'Unknown'
              for (const u in MCs.users.objects) {
                if (MCs.users.objects[u].id === this.data.updatedBy) {
                  this.data.updatedByName = MCs.users.objects[u].userName
                  break
                }
              }
              if (Object.prototype.hasOwnProperty.call(this.data, 'conversation')) {
                this.data.conversation.forEach(function (c, j) {
                  if (c.userID === WMEURMPT.me.getID()) {
                    c.userName = WMEURMPT.me.getUsername()
                    if (j === this.data.conversation.length - 1) {
                      this.lastVisitCommentsCount = this.data.conversation.length
                    }
                  }
                  for (const u in MCs.users.objects) {
                    if (MCs.users.objects[u].id === c.userID) {
                      c.userName = MCs.users.objects[u].userName
                      break
                    }
                  }
                }, this)
              } else {
                this.data.conversation = []
              }
            }
          }
          return haveChanged
        }
      }
      return null
    }
  }

  WMEURMPT.getMC = function (lon, lat, id) {
    const bounds = new OpenLayers.Bounds(lon - 0.01, lat - 0.01, lon + 0.01, lat + 0.01)
    const MCs = WMEURMPT.getMPs(bounds)
    if (MCs == null) {
      return null
    }
    if (id != null) {
      while (MCs.mapComments.objects.length >= 2) {
        for (let i = 0; i < MCs.mapComments.objects.length; i++) {
          if (MCs.mapComments.objects[i].id !== id) {
            MCs.mapComments.objects.splice(i, 1)
            break
          }
        }
      }
      if (MCs.mapComments.objects.length === 0) {
        return null
      }
      if (MCs.mapComments.objects[0].id !== id) {
        return null
      }
    }
    return MCs
  }

  WMEURMPT.URT_PUR = function (id, lon, lat) {
    this.id = id
    this.lonlat = new OpenLayers.LonLat(lon, lat)
    this.blackListed = false
    this.alreadyVisited = false
    this.refreshFromServer = refreshFromServer
    this.refreshFromWMEData = refreshFromWMEData
    this.distanceToMapCenter = 0
    this.clean = clean
    this.updateDistanceToMapCenter = updateDistanceToMapCenter
    function clean () {
      if (Object.prototype.hasOwnProperty.call(this.data, 'bounds') === true) {
        delete this.data.bounds
      }
      if (Object.prototype.hasOwnProperty.call(this.data, 'geometry') === true) {
        delete this.data.geometry
      }
    }
    function updateDistanceToMapCenter () {
      if (!WMEURMPT.isComputeDistances) {
        return
      }
      if (!WMEURMPT.mapCenterLonLat) {
        WMEURMPT.mapCenterLonLat = OpenLayers.Layer.SphericalMercator.inverseMercator(WMEURMPT.wazeMap.olMap.center.lon, WMEURMPT.wazeMap.olMap.center.lat)
      }
      const p1 = new OpenLayers.Geometry.Point(WMEURMPT.mapCenterLonLat.lon, WMEURMPT.mapCenterLonLat.lat)
      const p2 = new OpenLayers.Geometry.Point(this.lonlat.lon, this.lonlat.lat)
      const line = new OpenLayers.Geometry.LineString([p1, p2])
      this.distanceToMapCenter = line.getGeodesicLength(new OpenLayers.Projection('EPSG:4326'))
    }
    function refreshFromWMEData (forceSession) {
      const thePUR = WMEURMPT.wazeModel.venues.objects[this.id]
      WMEURMPT.logDebug('refreshFromWME PUR:', thePUR)
      if (thePUR == null) {
        return false
      }
      this.data = {};
      ['categories', 'name', 'createdBy', 'createdOn', 'streetID'].forEach(function (p) {
        this.data[p] = thePUR.attributes[p] === undefined ? 'undefined' : thePUR.attributes[p]
      }, this)
      this.data.createdByName = 'Unknown'
      for (const u in thePUR.model.users.objects) {
        if (thePUR.model.users.objects[u].id === this.data.createdBy) {
          this.data.createdByName = thePUR.model.users.objects[u].userName
          break
        }
      }
      this.data.updatedByName = 'Unknown'
      for (const u in thePUR.model.users.objects) {
        if (thePUR.model.users.objects[u].id === this.data.updatedBy) {
          this.data.updatedByName = thePUR.model.users.objects[u].userName
          break
        }
      }
      if (Object.prototype.hasOwnProperty.call(thePUR.attributes, 'venueUpdateRequests') && thePUR.attributes.venueUpdateRequests.length >> 0) {
        this.data.venueUpdateRequests = []
        this.data.dateAddedMin = 0
        this.data.dateAddedMax = 0
        for (let n = 0; n < thePUR.attributes.venueUpdateRequests.length; n++) {
          if (Object.prototype.hasOwnProperty.call(thePUR.attributes.venueUpdateRequests[n].changed, 'approved') && thePUR.attributes.venueUpdateRequests[n].changed.approved !== null) {
            thePUR.attributes.venueUpdateRequests.splice(n, 1)
            continue
          }
          this.data.venueUpdateRequests[n] = {};
          ['createdBy', 'dateAdded', 'type', 'updateType', 'subject'].forEach(function (p) {
            this.data.venueUpdateRequests[n][p] = thePUR.attributes.venueUpdateRequests[n].attributes[p] === undefined ? 'undefined' : thePUR.attributes.venueUpdateRequests[n].attributes[p]
          }, this)
          this.data.venueUpdateRequests[n].changed = thePUR.attributes.venueUpdateRequests[n].changed
          this.data.venueUpdateRequests[n].createdByName = 'Unknown'
          for (const u in thePUR.model.users.objects) {
            if (thePUR.model.users.objects[u].id === this.data.venueUpdateRequests[n].createdBy) {
              this.data.venueUpdateRequests[n].createdByName = thePUR.model.users.objects[u].userName
              break
            }
          }
          if (this.data.venueUpdateRequests[n].dateAdded << this.data.dateAddedMin) {
            this.data.dateAddedMin = this.data.venueUpdateRequests[n].dateAdded
          }
          if (this.data.venueUpdateRequests[n].dateAdded >> this.data.dateAddedMax) {
            this.data.dateAddedMax = this.data.venueUpdateRequests[n].dateAdded
          }
          WMEURMPT.logDebug('this.id: ' + this.id + '; this.data.venueUpdateRequests[' + n + '].dateAdded: ' + this.data.venueUpdateRequests[n].dateAdded, this)
        }
      } else if (Object.prototype.hasOwnProperty.call(thePUR.attributes, 'venueUpdateRequests') && thePUR.attributes.venueUpdateRequests.length === 0) {
        WMEURMPT.PURList.splice(WMEURMPT.PURMap[this.id], 1)
        WMEURMPT.PURMap = WMEURMPT.listToObject(WMEURMPT.PURList)
        this.clean()
        WMEURMPT.updateIHMFromPURList()
        return
      }
      this.clean()
      this.updateDistanceToMapCenter()
      WMEURMPT.updateIHMFromPURList()
      return true
    }

    function refreshFromServer () {
      let haveChanged = false
      WMEURMPT.log('refresh from server ' + this.id)
      const PURs = WMEURMPT.getPUR(this.lonlat.lon, this.lonlat.lat, this.id)
      if (PURs != null) {
        WMEURMPT.logDebug('refresh from server ' + this.id + ';', PURs)
        if (typeof PURs.venues !== 'undefined') {
          for (let i = 0; i < PURs.venues.objects.length; i++) {
            if (PURs.venues.objects[i].id === this.id) {
              if (this.data.updatedOn !== PURs.venues.objects[i].updatedOn) {
                haveChanged = true
              }
              WMEURMPT.logDebug('refresh from server ' + this.id + ';', PURs.venues.objects[i])
              this.data = PURs.venues.objects[i]
              if (this.data.name === 'undefined') {
                this.data.name = 'undefined'
              }
              this.data.createdByName = 'Unknown'
              for (const u in PURs.users.objects) {
                if (PURs.users.objects[u].id === this.data.createdBy) {
                  this.data.createdByName = PURs.users.objects[u].userName
                  break
                }
              }
              this.data.updatedByName = 'Unknown'
              for (const u in PURs.users.objects) {
                if (PURs.users.objects[u].id === this.data.updatedBy) {
                  this.data.updatedByName = PURs.users.objects[u].userName
                  break
                }
              }
              if (Object.prototype.hasOwnProperty.call(PURs.venues.objects[i], 'venueUpdateRequests') && PURs.venues.objects[i].venueUpdateRequests.length >> 0) {
                this.data.venueUpdateRequests = []
                this.data.dateAddedMin = 0
                this.data.dateAddedMax = 0
                for (let n = 0; n < PURs.venues.objects[i].venueUpdateRequests.length; n++) {
                  this.data.venueUpdateRequests[n] = {};
                  ['createdBy', 'dateAdded', 'type', 'updateType', 'subject'].forEach(function (p) {
                    this.data.venueUpdateRequests[n][p] = PURs.venues.objects[i].venueUpdateRequests[n].attributes[p] === undefined ? 'undefined' : PURs.venues.objects[i].venueUpdateRequests[n].attributes[p]
                  }, this)
                  this.data.venueUpdateRequests[n].changed = PURs.venues.objects[i].venueUpdateRequests[n].changed
                  this.data.venueUpdateRequests[n].createdByName = 'Unknown'
                  for (const u in PURs.model.users.objects) {
                    if (PURs.model.users.objects[u].id === this.data.venueUpdateRequests[n].createdBy) {
                      this.data.venueUpdateRequests[n].createdByName = PURs.model.users.objects[u].userName
                      break
                    }
                  }
                  if (this.data.venueUpdateRequests[n].dateAdded << this.data.dateAddedMin) {
                    this.data.dateAddedMin = this.data.venueUpdateRequests[n].dateAdded
                  }
                  if (this.data.venueUpdateRequests[n].dateAdded >> this.data.dateAddedMax) {
                    this.data.dateAddedMax = this.data.venueUpdateRequests[n].dateAdded
                  }
                }
              }
              WMEURMPT.logDebug('this: ', this)
            }
          }
          return haveChanged
        }
      }
      return null
    }
  }

  WMEURMPT.getPUR = function (lon, lat, id) {
    const bounds = new OpenLayers.Bounds(lon - 0.01, lat - 0.01, lon + 0.01, lat + 0.01)
    const PURs = WMEURMPT.getMPs(bounds)
    if (PURs == null) {
      return null
    }
    if (id != null) {
      WMEURMPT.log('getPUR PURs.venues :', PURs.venues)
      while (PURs.venues.objects.length >= 2) {
        for (let i = 0; i < PURs.venues.objects.length; i++) {
          if (PURs.venues.objects[i].id !== id) {
            PURs.venues.objects.splice(i, 1)
            break
          }
        }
      }
      if (PURs.venues.objects.length === 0) {
        return null
      }
      if (PURs.venues.objects[0].id !== id) {
        return null
      }
    }
    return PURs
  }

  WMEURMPT.URT_AREA = function () {
    this.name = ''
    this.category = ''
    this.subset = false
    this.parent = ''
    this.geometryWKT = ''
    this.geometryOL = null
    this.getGeometryFromServer = getGeometryFromServer
    this.getCategoryElementsFromServer = getCategoryElementsFromServer
    this.isInside = isInside
    function getGeometryFromServer (callback, serverIndex) {
      if (typeof serverIndex === 'undefined' || serverIndex == null) {
        serverIndex = 0
      }
      if (serverIndex >= WMEURMPT.servers.length) {
        callback(null)
        return
      }
      const url = WMEURMPT.servers[serverIndex].url + 'getArea.php?category=' + this.category + (this.subset === true ? '&subset=' + this.parent : '') + '&name=' + this.name
      const context = this
      WMEURMPT.log('Try to download area from server ' + WMEURMPT.servers[serverIndex].name)
      // eslint-disable-next-line no-undef
      downloadHelper.add(url, function (data) {
        if (data.status === 'success') {
          try {
            const jsonObj = JSON.parse(data.data)
            context.geometryWKT = jsonObj.geometry
            callback(context)
          } catch (e) {
            WMEURMPT.log('Error while getting area from server' + WMEURMPT.servers[serverIndex].name + '!', e)
            context.getGeometryFromServer(callback, serverIndex + 1)
          }
        } else {
          context.getGeometryFromServer(callback, serverIndex + 1)
        }
      }, null)
    }
    function getCategoryElementsFromServer (callback, serverIndex) {
      if (typeof serverIndex === 'undefined' || serverIndex === null) {
        serverIndex = 0
      }
      if (serverIndex >= WMEURMPT.servers.length) {
        WMEURMPT.errorOnCountryServer()
        return
      }
      const url = WMEURMPT.servers[serverIndex].url + 'getArea.php?category=' + this.category
      const context = this
      WMEURMPT.log('Try to download area list from server ' + WMEURMPT.servers[serverIndex].name)
      // eslint-disable-next-line no-undef
      downloadHelper.add(url, function (data) {
        if (data.status === 'success') {
          try {
            callback(JSON.parse(data.data))
          } catch (e) {
            WMEURMPT.log('Error while getting categories from server!', e)
            context.getCategoryElementsFromServer(callback, serverIndex + 1)
          }
        } else {
          context.getCategoryElementsFromServer(callback, serverIndex + 1)
        }
      }, null)
    }
    function isInside (lonlat) {
      const xy = new OpenLayers.Geometry.Point(lonlat.lon, lonlat.lat)
      let filterArea = []
      if ((this.category === 'country' || this.category === 'custom') && (this.geometryOL !== null)) {
        filterArea = this.geometryOL.geometry.components
      }
      for (let a = 0; a < filterArea.length; a++) {
        if (xy.x >= filterArea[a].bounds.left && xy.x <= filterArea[a].bounds.right && xy.y >= filterArea[a].bounds.bottom && xy.y <= filterArea[a].bounds.top) {
          if (Object.prototype.hasOwnProperty.call(filterArea[a], 'bintreeContainsPoint') === false) {
            if (filterArea[a].containsPoint(xy)) {
              return true
            }
          } else {
            if (filterArea[a].bintreeContainsPoint(xy)) {
              return true
            }
          }
        }
      }
      return false
    }
  }

  WMEURMPT.info = function (text) {
    text = typeof text !== 'undefined' ? text : ''
    const div = WMEURMPT.getId('urt-info')
    div.innerHTML = WMEURMPT.convertHtml(text)
  }

  WMEURMPT.saveOptions = function () {
    const options = {
      filterUR: WMEURMPT.currentURFilter,
      filterMP: WMEURMPT.currentMPFilter,
      filterMC: WMEURMPT.currentMCFilter,
      filterPUR: WMEURMPT.currentPURFilter,
      filterURKeyword: WMEURMPT.currentURKeyWord,
      filterMCKeyword: WMEURMPT.currentMCKeyWord,
      filterPURKeyword: WMEURMPT.currentPURKeyWord,
      filterURLimitTo: WMEURMPT.currentURLimitTo,
      filterMPLimitTo: WMEURMPT.currentMPLimitTo,
      filterMCLimitTo: WMEURMPT.currentMCLimitTo,
      filterPURLimitTo: WMEURMPT.currentPURLimitTo,
      displayLegend: WMEURMPT.displayLegend,
      isEnabled: WMEURMPT.isEnabled,
      isAutoScan: WMEURMPT.isAutoScan,
      isComputeDistances: WMEURMPT.isComputeDistances,
      scanUR: WMEURMPT.scanUR,
      scanMP: WMEURMPT.scanMP,
      scanMC: WMEURMPT.scanMC,
      scanPUR: WMEURMPT.scanPUR,
      filterUROnlyType: WMEURMPT.currentUROnlyType,
      filterMPOnlyType: WMEURMPT.currentMPOnlyType,
      filterPUROnlyCategorie: WMEURMPT.currentPUROnlyCategorie,
      filterUROnlyArea: WMEURMPT.currentUROnlyArea,
      filterMPOnlyArea: WMEURMPT.currentMPOnlyArea,
      filterMCOnlyArea: WMEURMPT.currentMCOnlyArea,
      filterPUROnlyArea: WMEURMPT.currentPUROnlyArea,
      filterURCommentsCount: WMEURMPT.currentURCommentsCount,
      URDescriptionMaxLength: WMEURMPT.URDescriptionMaxLength,
      MPDescriptionMaxLength: WMEURMPT.MPDescriptionMaxLength,
      MCSubjectMaxLength: WMEURMPT.MCSubjectMaxLength,
      MCBodyMaxLength: WMEURMPT.MCBodyMaxLength,
      PURCategoriesMaxLength: WMEURMPT.PURCategoriesMaxLength,
      PURNameMaxLength: WMEURMPT.PURNameMaxLength,
      taggedURList: WMEURMPT.taggedURList,
      URAgeColIsLastComment: WMEURMPT.URAgeColIsLastComment,
      disableScrolling: WMEURMPT.disableScrolling,
      purInvertFilter: WMEURMPT.purInvertFilter,
      urtInvertFilter: WMEURMPT.urtInvertFilter
    }
    WMEURMPT.log('save options: ', options)
    // eslint-disable-next-line no-undef
    GMStorageHelper.save('WMEURMPTracking_options', JSON.stringify(options))
  }

  WMEURMPT.saveAreas = function () {
    // eslint-disable-next-line no-undef
    GMStorageHelper.save('WMEURMPTracking_areaList', JSON.stringify(WMEURMPT.areaList, function (key, value) {
      if (key === 'geometryOL') {
        return
      }
      return value
    }))
  }

  WMEURMPT.saveURList = function () {
    // eslint-disable-next-line no-undef
    GMStorageHelper.save('WMEURMPTracking_URList', JSON.stringify(WMEURMPT.URList))
  }

  WMEURMPT.saveMPList = function () {
    // eslint-disable-next-line no-undef
    GMStorageHelper.save('WMEURMPTracking_MPList', JSON.stringify(WMEURMPT.MPList))
  }

  WMEURMPT.saveMCList = function () {
    // eslint-disable-next-line no-undef
    GMStorageHelper.save('WMEURMPTracking_MCList', JSON.stringify(WMEURMPT.MCList))
  }

  WMEURMPT.savePURList = function () {
    // eslint-disable-next-line no-undef
    GMStorageHelper.save('WMEURMPTracking_PURList', JSON.stringify(WMEURMPT.PURList))
  }

  WMEURMPT.saveURMPLists = function () {
    WMEURMPT.saveURList()
    WMEURMPT.saveMPList()
    WMEURMPT.saveMCList()
    WMEURMPT.savePURList()
  }

  WMEURMPT.save = function () {
    delete localStorage.WMEURTracking_options
    delete localStorage.WMEURTracking_URList
    delete localStorage.WMEURTracking_MPList
    delete localStorage.WMEURMPTracking_URList
    delete localStorage.WMEURMPTracking_MPList
    delete localStorage.WMEURMPTracking_PURList
    delete localStorage.WMEURMPTracking_options
    delete localStorage.WMEURMPTracking_URList_z
    delete localStorage.WMEURMPTracking_MPList_z
    WMEURMPT.saveOptions()
    WMEURMPT.saveAreas()
    WMEURMPT.saveURMPLists()
    WMEURMPT.log('Options and data saved')
  }

  WMEURMPT.optionsLoaded = function (data) {
    if (data.data != null) {
      const options = JSON.parse(data.data)
      WMEURMPT.log('GM options:', options)
      WMEURMPT.currentURFilter = typeof options.filterUR === 'undefined' ? WMEURMPT.URFilterList.hideClosed + WMEURMPT.URFilterList.hideBlacklisted : options.filterUR
      WMEURMPT.currentMPFilter = typeof options.filterMP === 'undefined' ? WMEURMPT.MPFilterList.hideClosed + WMEURMPT.MPFilterList.hideBlacklisted : options.filterMP
      WMEURMPT.currentMCFilter = typeof options.filterMC === 'undefined' ? WMEURMPT.MCFilterList.hideBlacklisted : options.filterMC
      WMEURMPT.currentPURFilter = typeof options.filterPUR === 'undefined' ? WMEURMPT.PURFilterList.hideBlacklisted : options.filterPUR
      WMEURMPT.currentURKeyWord = typeof options.filterURKeyword === 'undefined' ? WMEURMPT.loginManager.user.getUsername() : options.filterURKeyword
      WMEURMPT.currentMCKeyWord = typeof options.filterMCKeyword === 'undefined' ? WMEURMPT.loginManager.user.getUsername() : options.filterMCKeyword
      WMEURMPT.currentPURKeyWord = typeof options.filterPURKeyword === 'undefined' ? WMEURMPT.loginManager.user.getUsername() : options.filterPURKeyword
      WMEURMPT.currentURLimitTo = typeof options.filterURLimitTo === 'undefined' ? 100 : options.filterURLimitTo
      WMEURMPT.currentMPLimitTo = typeof options.filterMPLimitTo === 'undefined' ? 100 : options.filterMPLimitTo
      WMEURMPT.currentMCLimitTo = typeof options.filterMCLimitTo === 'undefined' ? 100 : options.filterMCLimitTo
      WMEURMPT.currentPURLimitTo = typeof options.filterPURLimitTo === 'undefined' ? 100 : options.filterPURLimitTo
      WMEURMPT.displayLegend = typeof options.displayLegend === 'undefined' ? true : options.displayLegend
      WMEURMPT.isEnabled = typeof options.isEnabled === 'undefined' ? true : options.isEnabled
      WMEURMPT.countryFilterList = typeof options.countryFilterList === 'undefined' ? [] : options.countryFilterList
      WMEURMPT.isComputeDistances = typeof options.isComputeDistances === 'undefined' ? true : options.isComputeDistances
      WMEURMPT.isAutoScan = typeof options.isAutoScan === 'undefined' ? true : options.isAutoScan
      WMEURMPT.scanUR = typeof options.scanUR === 'undefined' ? true : options.scanUR
      WMEURMPT.scanMP = typeof options.scanMP === 'undefined' ? true : options.scanMP
      WMEURMPT.scanMC = typeof options.scanMC === 'undefined' ? true : options.scanMC
      WMEURMPT.scanPUR = typeof options.scanPUR === 'undefined' ? true : options.scanPUR
      WMEURMPT.currentUROnlyType = typeof options.filterUROnlyType === 'undefined' ? WMEURMPT.currentUROnlyType : options.filterUROnlyType
      WMEURMPT.currentMPOnlyType = typeof options.filterMPOnlyType === 'undefined' ? WMEURMPT.currentMPOnlyType : options.filterMPOnlyType
      WMEURMPT.currentPUROnlyCategorie = typeof options.filterPUROnlyCategorie === 'undefined' ? WMEURMPT.currentPUROnlyCategorie : options.filterPUROnlyCategorie
      WMEURMPT.currentUROnlyArea = typeof options.filterUROnlyArea === 'undefined' ? WMEURMPT.currentUROnlyArea : options.filterUROnlyArea
      WMEURMPT.currentMPOnlyArea = typeof options.filterMPOnlyArea === 'undefined' ? WMEURMPT.currentMPOnlyArea : options.filterMPOnlyArea
      WMEURMPT.currentMCOnlyArea = typeof options.filterMCOnlyArea === 'undefined' ? WMEURMPT.currentMCOnlyArea : options.filterMCOnlyArea
      WMEURMPT.currentPUROnlyArea = typeof options.filterPUROnlyArea === 'undefined' ? WMEURMPT.currentPUROnlyArea : options.filterPUROnlyArea
      WMEURMPT.currentURCommentsCount = typeof options.filterURCommentsCount === 'undefined' ? WMEURMPT.currentURCommentsCount : options.filterURCommentsCount
      WMEURMPT.URDescriptionMaxLength = typeof options.URDescriptionMaxLength === 'undefined' ? WMEURMPT.URDescriptionMaxLength : options.URDescriptionMaxLength
      WMEURMPT.MPDescriptionMaxLength = typeof options.MPDescriptionMaxLength === 'undefined' ? WMEURMPT.MPDescriptionMaxLength : options.MPDescriptionMaxLength
      WMEURMPT.MCSubjectMaxLength = typeof options.MCSubjectMaxLength === 'undefined' ? WMEURMPT.MCSubjectMaxLength : options.MCSubjectMaxLength
      WMEURMPT.MCBodyMaxLength = typeof options.MCBodyMaxLength === 'undefined' ? WMEURMPT.MCBodyMaxLength : options.MCBodyMaxLength
      WMEURMPT.PURCategoriesMaxLength = typeof options.PURCategoriesMaxLength === 'undefined' ? WMEURMPT.PURCategoriesMaxLength : options.PURCategoriesMaxLength
      WMEURMPT.PURNameMaxLength = typeof options.PURNameMaxLength === 'undefined' ? WMEURMPT.PURNameMaxLength : options.PURNameMaxLength
      WMEURMPT.taggedURList = typeof options.taggedURList === 'undefined' ? WMEURMPT.taggedURList : options.taggedURList
      WMEURMPT.URAgeColIsLastComment = typeof options.URAgeColIsLastComment === 'undefined' ? WMEURMPT.URAgeColIsLastComment : options.URAgeColIsLastComment
      WMEURMPT.disableScrolling = typeof options.disableScrolling === 'undefined' ? WMEURMPT.disableScrolling : options.disableScrolling
      WMEURMPT.purInvertFilter = typeof options.purInvertFilter === 'undefined' ? WMEURMPT.purInvertFilter : options.purInvertFilter
      WMEURMPT.urtInvertFilter = typeof options.urtInvertFilter === 'undefined' ? WMEURMPT.urtInvertFilter : options.urtInvertFilter
    }
  }

  WMEURMPT.urlistLoaded = function (data) {
    if (data.data != null) {
      WMEURMPT.URList = JSON.parse(data.data)
      for (let i = 0; i < WMEURMPT.URList.length; i++) {
        const urtmp = new WMEURMPT.URT_UR(WMEURMPT.URList[i].id, WMEURMPT.URList[i].lonlat.lon, WMEURMPT.URList[i].lonlat.lat)
        WMEURMPT.URList[i].refreshFromServer = urtmp.refreshFromServer
        WMEURMPT.URList[i].refreshFromWMEData = urtmp.refreshFromWMEData
        WMEURMPT.URList[i].clean = urtmp.clean
        WMEURMPT.URList[i].updateDistanceToMapCenter = urtmp.updateDistanceToMapCenter
        if (Object.prototype.hasOwnProperty.call(WMEURMPT.URList[i], 'lastVisitCommentsCount') === false) {
          WMEURMPT.URList[i].lastVisitCommentsCount = 0
        }
        if (Object.prototype.hasOwnProperty.call(WMEURMPT.URList[i].data, 'session') === false) {
          WMEURMPT.log('Bad UR record. Trying to fix it...', WMEURMPT.URList[i].data)
          WMEURMPT.URList[i].refreshFromServer()
          WMEURMPT.log('Bad UR record. should be fixed:', WMEURMPT.URList[i].data)
        }
      }
      WMEURMPT.URMap = WMEURMPT.listToObject(WMEURMPT.URList)
    }
  }

  WMEURMPT.mplistLoaded = function (data) {
    if (data.data != null) {
      WMEURMPT.MPList = JSON.parse(data.data)
      for (let i = 0; i < WMEURMPT.MPList.length; i++) {
        const mptmp = new WMEURMPT.URT_MP(WMEURMPT.MPList[i].id, WMEURMPT.MPList[i].lonlat.lon, WMEURMPT.MPList[i].lonlat.lat)
        WMEURMPT.MPList[i].refreshFromServer = mptmp.refreshFromServer
        WMEURMPT.MPList[i].refreshFromWMEData = mptmp.refreshFromWMEData
        WMEURMPT.MPList[i].clean = mptmp.clean
        WMEURMPT.MPList[i].updateDistanceToMapCenter = mptmp.updateDistanceToMapCenter
      }
      WMEURMPT.MPMap = WMEURMPT.listToObject(WMEURMPT.MPList)
    }
  }
  WMEURMPT.mclistLoaded = function (data) {
    if (data.data != null) {
      WMEURMPT.MCList = JSON.parse(data.data)
      for (let i = 0; i < WMEURMPT.MCList.length; i++) {
        const mctmp = new WMEURMPT.URT_MC(WMEURMPT.MCList[i].id, WMEURMPT.MCList[i].lonlat.lon, WMEURMPT.MCList[i].lonlat.lat)
        if (Object.prototype.hasOwnProperty.call(WMEURMPT.MCList[i], 'lastVisitCommentsCount') === false) {
          WMEURMPT.MCList[i].lastVisitCommentsCount = 0
        }
        WMEURMPT.MCList[i].refreshFromServer = mctmp.refreshFromServer
        WMEURMPT.MCList[i].refreshFromWMEData = mctmp.refreshFromWMEData
        WMEURMPT.MCList[i].clean = mctmp.clean
        WMEURMPT.MCList[i].updateDistanceToMapCenter = mctmp.updateDistanceToMapCenter
      }
      WMEURMPT.MCMap = WMEURMPT.listToObject(WMEURMPT.MCList)
    }
  }

  WMEURMPT.purlistLoaded = function (data) {
    if (data.data != null) {
      WMEURMPT.PURList = JSON.parse(data.data)
      for (let i = 0; i < WMEURMPT.PURList.length; i++) {
        const purtmp = new WMEURMPT.URT_PUR(WMEURMPT.PURList[i].id, WMEURMPT.PURList[i].lonlat.lon, WMEURMPT.PURList[i].lonlat.lat)
        WMEURMPT.PURList[i].refreshFromServer = purtmp.refreshFromServer
        WMEURMPT.PURList[i].refreshFromWMEData = purtmp.refreshFromWMEData
        WMEURMPT.PURList[i].clean = purtmp.clean
        WMEURMPT.PURList[i].updateDistanceToMapCenter = purtmp.updateDistanceToMapCenter
      }
      WMEURMPT.PURMap = WMEURMPT.listToObject(WMEURMPT.PURList)
    }
  }

  WMEURMPT.arealistLoaded = function (data) {
    if (data.data != null) {
      WMEURMPT.areaList = JSON.parse(data.data)
      for (let c = 0; c < WMEURMPT.areaList.country.length; c++) {
        const areatmp = new WMEURMPT.URT_AREA()
        WMEURMPT.areaList.country[c].geometryOL = null
        WMEURMPT.areaList.country[c].getGeometryFromServer = areatmp.getGeometryFromServer
        WMEURMPT.areaList.country[c].getCategoryElementsFromServer = areatmp.getCategoryElementsFromServer
        WMEURMPT.areaList.country[c].isInside = areatmp.isInside
      }
      for (let c = 0; c < WMEURMPT.areaList.custom.length; c++) {
        const areatmp = new WMEURMPT.URT_AREA()
        WMEURMPT.areaList.custom[c].geometryOL = null
        WMEURMPT.areaList.custom[c].getGeometryFromServer = areatmp.getGeometryFromServer
        WMEURMPT.areaList.custom[c].getCategoryElementsFromServer = areatmp.getCategoryElementsFromServer
        WMEURMPT.areaList.custom[c].isInside = areatmp.isInside
      }
    }
    window.setTimeout(WMEURMPT.initialiseURT, 1000)
  }

  WMEURMPT.load = function () {
    try {
      WMEURMPT.dictionary['"' + WMEURMPT.me.getUsername() + '"'] = '~Z'

      GMStorageHelper.load('WMEURMPTracking_options', WMEURMPT.optionsLoaded)
      GMStorageHelper.load('WMEURMPTracking_URList', WMEURMPT.urlistLoaded)
      GMStorageHelper.load('WMEURMPTracking_MPList', WMEURMPT.mplistLoaded)
      GMStorageHelper.load('WMEURMPTracking_MCList', WMEURMPT.mclistLoaded)
      GMStorageHelper.load('WMEURMPTracking_PURList', WMEURMPT.purlistLoaded)
      GMStorageHelper.load('WMEURMPTracking_areaList', WMEURMPT.arealistLoaded)
    } catch (err) {
      WMEURMPT.log('Error while loading data from storage: ', err)
    }
  }

  WMEURMPT.PopupPannel = function (name, w, h, bgcolor) {
    this.name = name
    this.w = w
    this.h = h
    this.pannel_elt = WMEURMPT.createElement('div', 'popup-pannel-' + name)
    this.pannel_elt.className = 'popup-pannel-class-' + name
    this.pannel_elt.style.width = w
    this.pannelTrigger_elt = WMEURMPT.createElement('div', 'popup-pannel-trigger-' + name)
    this.pannelTrigger_elt.className = 'popup-pannel-trigger-class-' + name
    this.pannelTrigger_elt.onclick = WMEURMPT.getFunctionWithArgs(triggerMouseOver, [name, w, h])
    this.pannelTrigger_elt.style.backgroundColor = bgcolor
    this.pannelContents_elt = WMEURMPT.createElement('div', 'popup-pannel-contents-' + name)
    this.pannelContents_elt.className = 'popup-pannel-contents-closed-class-' + name
    this.pannelContents_elt.style.backgroundColor = bgcolor
    this.pannel_elt.appendChild(this.pannelTrigger_elt)
    this.pannel_elt.appendChild(this.pannelContents_elt)
    this.installInside = installInside
    this.setTriggerInnerHTML = setTriggerInnerHTML
    this.setContentsInnerHTML = setContentsInnerHTML
    function triggerMouseOver (name, w, h) {
      const elt = document.getElementById('popup-pannel-contents-' + name)
      elt.style.width = w
      elt.style.height = h
      elt.className = 'popup-pannel-contents-open-class-' + name
      const triggerElt = document.getElementById('popup-pannel-trigger-' + name)
      triggerElt.style.borderBottomRightRadius = '0px'
      triggerElt.style.borderBottomLeftRadius = '0px'
      window.setTimeout(function () {
        document.getElementById('popup-pannel-contents-' + name).onmouseleave = function (e) {
          const elementMouseIsOver = document.elementFromPoint(e.clientX, e.clientY)
          if (WMEURMPT.isDescendant(this, elementMouseIsOver)) {
            return
          }
          panelMouseLeave(name)
        }
        document.getElementById('popup-pannel-' + name).onmouseleave = function (e) {
          const elementMouseIsOver = document.elementFromPoint(e.clientX, e.clientY)
          if (WMEURMPT.isDescendant(this, elementMouseIsOver)) {
            return
          }
          panelMouseLeave(name)
        }
      }, 100)
    }
    function panelMouseLeave (name) {
      const elt = document.getElementById('popup-pannel-contents-' + name)
      elt.style.width = '0px'
      elt.style.height = '0px'
      elt.className = 'popup-pannel-contents-closed-class-' + name
      const triggerElt = document.getElementById('popup-pannel-trigger-' + name)
      triggerElt.style.borderBottomRightRadius = '5px'
      triggerElt.style.borderBottomLeftRadius = '5px'
      document.getElementById('popup-pannel-contents-' + name).onmouseleave = null
      document.getElementById('popup-pannel-' + name).onmouseleave = null
    }
    function setTriggerInnerHTML (htmltext) {
      this.pannelTrigger_elt.innerHTML = WMEURMPT.convertHtml(htmltext)
    }
    function setContentsInnerHTML (htmltext) {
      this.pannelContents_elt.innerHTML = WMEURMPT.convertHtml(htmltext)
    }
    function installInside (node) {
      const cssElt = WMEURMPT.createElement('style')
      cssElt.type = 'text/css'
      let css = ''
      css += '.popup-pannel-class-' + this.name + ' { margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; padding-bottom: 2px; padding-top: 2px; padding-left: 5px; padding-right: 5px; }'
      css += '.popup-pannel-trigger-class-' + this.name + ' { cursor: pointer; align: right; border-top-left-radius: 5px; border-top-right-radius: 5px; border-bottom-right-radius: 5px; border-bottom-left-radius: 5px; padding-bottom: 2px; padding-top: 2px; padding-left: 5px; padding-right: 5px;}'
      css += '.popup-pannel-contents-closed-class-' + this.name + ' { float: left; position: relative; left: 0px; width: 0px; height: 0px; overflow: hidden;}'
      css += '.popup-pannel-contents-open-class-' + this.name + ' { float: left; position: relative; left: 0px; width: 0px; height: 0px; overflow: hidden; border-bottom-right-radius: 5px; border-bottom-left-radius: 5px; padding-bottom: 2px; padding-top: 2px; padding-left: 5px; padding-right: 5px;}'
      cssElt.innerHTML = WMEURMPT.convertHtml(css)
      document.body.appendChild(cssElt)
      node.appendChild(this.pannel_elt)
    }
  }

  WMEURMPT.dict_traduce = function (str, dict) {
    str = str.replace(/,"distanceToMapCenter":\d*\.\d*/g, '')
    str = str.replace(/,"descriptionOffset":-?\d*/g, '')
    str = str.replace(/(\d*\.\d{6})\d+/g, '$1')
    for (const word in dict) {
      if (Object.prototype.hasOwnProperty.call(dict, word)) {
        str = str.replace(new RegExp(word, 'g'), dict[word])
      }
    }
    return str
  }

  WMEURMPT.dictionary = {
    '"lonlat":': '~a',
    '"blackListed":': '~b',
    '"alreadyVisited":': '~c',
    '"lon":': '~d',
    '"lat":': '~e',
    '"data":': '~f',
    '"description":': '~g',
    '"driveDate":': '~h',
    '"hasComments":': '~i',
    '"resolution":': '~j',
    '"resolvedBy":': '~k',
    '"resolvedOn":': '~l',
    '"type":': '~m',
    '"updatedBy":': '~n',
    '"updatedOn":': '~o',
    '"resolvedByName":': '~p',
    '"session":': '~q',
    '"comments":': '~r',
    '"mapUpdateRequestID":': '~s',
    '"createdOn":': '~t',
    '"userID":': '~v',
    '"text":': '~w',
    '"userName":': '~x',
    '"isFollowing":': '~y',
    false: '~z',
    true: '~A',
    '"open":': '~B',
    null: '~C',
    '"problem":': '~D',
    '"priority":': '~E',
    '"problemType":': '~F',
    '"weight":': '~G',
    '"id":': '~H',
    '"descriptionOffset":': '~I',
    '"Reporter"': '~J',
    '"Unknown"': '~K',
    '"updated":': '~L',
    '"rank":': '~M',
    '"permissions":': '~N',
    '"version":': '~O',
    '"isReporterFollowing":': '~P',
    '"lastVisitCommentsCount":': '~Q',
    '"problem"': '~R',
    '"turnProblem"': '~S'
  }
  WMEURMPT.rl4cp = 2
  WMEURMPT.shuffleArray(WMEURMPT.servers)
  WMEURMPT.log('Ready')
  WMEURMPT.bootstrapURT()
}

GM_addElement('script', {
  // eslint-disable-next-line quotes, camelcase
  textContent: '' + WMEURMPT_Injected.toString() + "\nWMEURMPT_Injected();"
})