diff --git a/.gitignore b/.gitignore index 7e07ab4..a17a2e8 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ .idea/workspace.xml .vs/* *.pyproj +quick_config_slyce.json diff --git a/README.md b/README.md index db79e05..509b8f5 100644 --- a/README.md +++ b/README.md @@ -74,6 +74,23 @@ pyglet is used to play the sound – If it is not available the sound option wil https://pypi.python.org/pypi/requests - Six for python 3 compatibility https://pypi.python.org/pypi/six +## Note for windows users + +The anaconda python package will come with most of what you need [download](https://www.continuum.io/downloads#windows). +vintel compilation has been tested with 64 bit anaconda2 v4.2.0 for python 2.7 on windows 10. + +You will need to run these two commands to downgrade qt5 to qt4 and install the pyglet package. If you installed anaconda for all +users, you may need to run them in an *admin* anaconda prompt. + +``` +conda install pyqt=4 +pip install pyglet +``` + +## Note for cygwin users + +pyglet doesn't currently work under cygwin. Skip installing it or pip uninstall if it causes problems. + ## Building the Vintel Standalone Package - The standalone is created using pyinstaller. All media files and the .spec-file with the configuration for pyinstaller are included in the source repo. Pyinstaller can be found here: https://github.com/pyinstaller/pyinstaller/wiki. diff --git a/SETUP.md b/SETUP.md new file mode 100644 index 0000000..d798e21 --- /dev/null +++ b/SETUP.md @@ -0,0 +1,127 @@ +# Vintel Setup + +This document describes the settings available in the Vintel application. + +## Settings Dialog + +The settings dialog has three panes: *Quick Setup*, *Jumpbridges*, and *Chat Channels*. + +The *Jumpbridges* pane allows you to specify a source for jumpbridges to be +rendered on the maps. You may specify either a DOTLAN jumpbridge list id or an URL to +a file containing your own jumpbridge list. More details on the format of the file +can be seen in the application pane or in *Quick Setup* below. + +The *Chat Channels* pane allows you to specify EVE chat channels to monitor for +intelligence reports. You must keep this chat channel open in a tab in game +and have *Log Chat to File* selected in EVE Settings > Chat. Vintel monitors and +processes these log files on your local disk. + +## Quick Setup + +The first pane of the settings allows you to paste a quick configuration JSON +blob that may be provided by your alliance. + +1. **dotlan_jb_id** The id of a jumpbridge list from DOTLAN. Include just the id, + i.e. from http://evemaps.dotlan.net/bridges/**XXXXxxxx** use the XXXXxxxx +2. **jumpbridge_url** A url to a file containing your bridge list. Each line + in the file should contain two systems separated by a `<->`. i.e. + `HED-GP <-> 36N-HZ` +3. **channels** A JSON list of the channels to be monitored. +4. **kos_url** A URL to your alliances KOS server. +5. **region_name** The default region to load on launch. Later, the application will + remember the last region viewed and load that when you restart. +6. **quick_regions** The regions listed here are automatically added to the + application's *Region* menu. Any name starting with a dash will be interpreted + as a separator and will draw a horizontal line between entries. Each entry + should have a **label** field which is how it will appear in the menu. Each + may also have a **region** field which can be used to override the region name + used when looking up this system on DOTLAN if the label is not an exact match + (spaces will be automatically converted to underscores). + + The **region** should match a DOTLAN url - i.e. http://evemaps.dotlan.net/map/**Catch**. + The **region** can also be one of the special or combined maps listed at the + bottom of the DOTLAN universe page. Vintel also recognizes the custom region + providencecatch. + +This is what the Vintel defaults would look like as a quick configuration entry: + +``` +{ + "dotlan_jb_id": "", + "jumpbridge_url": "", + "channels": [ + "TheCitadel", + "North Provi Intel", + "North Catch Intel", + "North Querious Intel" + ], + "kos_url": "http://kos.cva-eve.org/api/", + "region_name": "Catch", + "quick_regions": [ + {"label": "Catch"}, + {"label": "Providence"}, + {"label": "Querious"}, + {"label": "---"}, + {"label": "Provi / Catch", "region": "providencecatch"}, + {"label": "Provi / Catch (compact)", "region": "Providence-catch"} + ] +} +``` + +## Other Menu Settings + +### File > Clear Cache + +If you notice any weirdness with maps or avatars, you may try flushing the Vintel +cache. Avatars and maps will be redownloaded. + +### Chat > Show Chat + +Hide the chat history on the right side of the screen + +### Chat > Show Chat Avatars + +Do not show character portraits in the chat history. Unfortunately selecting this +doesn't yet make the chat window more compact. + +### Sound > Activate Sound + +This should be checked to enable sound in Vintel. + +### Sound > Sound Setup ... + +Test the sound configuration. + +### Sound > Spoken Notifications + +Doesn't work on Windows 10, what does it do? + +### Region + +Select a region from the quick region shortcuts configured in *Quick Settings* + +### Region > Other Region + +Select from a list of all known EVE regions. + +### Region > Custom Region ... + +Displays a freeform text box to enter a standard or custom region by name. + +### K.O.S. + +Activate some of the Kill On Sight processing and warnings. + +### Window > Always On Top + +Keep this window above all other windows. + +### Window > Frameless Main Window + +Remove OS decorations from the window: titlebar, menubar, ... Once activated a *Restore Frame* button will +be available in the upper left corner of the screen. Click that to restore the window decorations. + +### Window > Transparency + +Set the window opacity. + diff --git a/quick_config_cva.json b/quick_config_cva.json new file mode 100644 index 0000000..e37c46f --- /dev/null +++ b/quick_config_cva.json @@ -0,0 +1,20 @@ +{ + "dotlan_jb_id": "", + "jumpbridge_url": "", + "channels": [ + "TheCitadel", + "North Provi Intel", + "North Catch Intel", + "North Querious Intel" + ], + "kos_url": "http://kos.cva-eve.org/api/", + "region_name": "Catch", + "quick_regions": [ + {"label": "Catch"}, + {"label": "Providence"}, + {"label": "Querious"}, + {"label": "---"}, + {"label": "Provi / Catch", "region": "providencecatch"}, + {"label": "Provi / Catch (compact)", "region": "Providence-catch"} + ] +} diff --git a/src/conda2_launcher.py b/src/conda2_launcher.py new file mode 100644 index 0000000..8ea9db2 --- /dev/null +++ b/src/conda2_launcher.py @@ -0,0 +1,27 @@ +# This is a windows shortcut helper, +# +# Setup a shortcut using your ananconda installation directory and your vintel source triggered +# "E:\Program Files\Anaconda2\pythonw.exe" "\FULL\PATH\TO\src\vintel\src\conda2_launcher.py" "E:\Program File\Anaconda2" +# +# It is based on the cwp.py script included with ananconda, but that script is hardcoded to switch +# the current working directory to the user's home directory on launch + +import os +import sys +import subprocess +from os.path import join + +prefix = sys.argv[1] + +env = os.environ.copy() +env['PATH'] = os.path.pathsep.join([ + prefix, + join(prefix, "Scripts"), + join(prefix, "Library", "bin"), + env['PATH'], +]) + +dir = os.path.abspath(os.path.dirname(__file__)) +print("prefix=[%s], dir=[%s]" % (prefix, dir)) +os.chdir(os.path.abspath(os.path.dirname(__file__))) +subprocess.call([sys.executable, "vintel.py"], env=env) diff --git a/src/vi/cache/cache.py b/src/vi/cache/cache.py index 3d0837b..6863556 100644 --- a/src/vi/cache/cache.py +++ b/src/vi/cache/cache.py @@ -21,6 +21,7 @@ import threading import time import six +import sys if six.PY2: def to_blob(x): return buffer(str(x)) @@ -30,11 +31,14 @@ def from_blob(x): def to_blob(x): return x def from_blob(x): - return x + return x[0][0] import logging from vi.cache.dbstructure import updateDatabase +ONE_DAY = 60 * 60 * 24 +DEFAULT_TIME = ONE_DAY * 3 +PERMANENT = ONE_DAY * 365 class Cache(object): # Cache checks PATH_TO_CACHE when init, so you can set this on a @@ -74,8 +78,8 @@ def checkVersion(self): raise e updateDatabase(version, self.con) - def putIntoCache(self, key, value, maxAge=60 * 60 * 24 * 3): - """ Putting something in the cache maxAge is maximum age in seconds + def putIntoCache(self, key, value, maxAge=DEFAULT_TIME): + """ Putting something in the cache maxAge is maximum age in seconds, default is 3 days """ with Cache.SQLITE_WRITE_LOCK: query = "DELETE FROM cache WHERE key = ?" @@ -98,6 +102,32 @@ def getFromCache(self, key, outdated=False): else: return founds[0][1] + def getConfigValue(self, key): + """ Retrieve a config value from cache that never expires + """ + return self.getFromCache(key, True) + + def saveConfigValue(self, key, value): + """ Save a config value to cache that never expires + """ + return self.putIntoCache(key, value, sys.maxsize) + + def deleteFromCache(self, key): + """ Deleteing from cache + """ + with Cache.SQLITE_WRITE_LOCK: + query = "DELETE FROM cache WHERE key = ?" + self.con.execute(query, (key,)) + self.con.commit() + + def flush(self): + """ Flush non config items from cache + """ + with Cache.SQLITE_WRITE_LOCK: + query = "DELETE FROM cache WHERE maxAge < ?" + self.con.execute(query, (sys.maxsize,)) + self.con.commit() + def putPlayerName(self, name, status): """ Putting a playername into the cache """ @@ -138,8 +168,8 @@ def getAvatar(self, name): if len(founds) == 0: return None else: - # dats is buffer, we convert it back to str - data = from_blob(founds[0][0]) + # data is buffer, we convert it back to str + data = from_blob(founds) return data def removeAvatar(self, name): @@ -161,5 +191,3 @@ def recallAndApplySettings(self, responder, settingsIdentifier): getattr(obj, setting[1])(setting[2]) except Exception as e: logging.error(e) - - diff --git a/src/vi/chatparser/chatparser.py b/src/vi/chatparser/chatparser.py index 8d7ac21..4674a0b 100644 --- a/src/vi/chatparser/chatparser.py +++ b/src/vi/chatparser/chatparser.py @@ -20,32 +20,36 @@ import datetime import os import time +import logging import six if six.PY2: from io import open from bs4 import BeautifulSoup -from vi import states +from vi import states, evegate from PyQt4.QtGui import QMessageBox - from .parser_functions import parseStatus from .parser_functions import parseUrls, parseShips, parseSystems # Names the local chatlogs could start with (depends on l10n of the client) -LOCAL_NAMES = ("Local", "Lokal", six.text_type("\u041B\u043E\u043A\u0430\u043B\u044C\u043D\u044B\u0439")) +LOCAL_NAMES = ("local", "lokal", six.text_type("\u041B\u043E\u043A\u0430\u043B\u044C\u043D\u044B\u0439").lower()) class ChatParser(object): """ ChatParser will analyze every new line that was found inside the Chatlogs. """ - def __init__(self, path, rooms, systems): + def HEADER_SIZE(self): return 13 + def REPLAY_SIZE(self): return 500 # retreive up to 500 lines from a logfile when starting up + + def __init__(self, path, rooms, allSystems, messageExpirySecs): """ path = the path with the logs rooms = the rooms to parse""" + self.messageExpirySecs = messageExpirySecs self.path = path # the path with the chatlog - self.rooms = rooms # the rooms to watch (excl. local) - self.systems = systems # the known systems as dict name: system + self.rooms = [r.lower() for r in rooms] # the rooms to watch (excl. local) + self.allSystems = allSystems # the known systems as dict name: system self.fileData = {} # informations about the files in the directory self.knownMessages = [] # message we allready analyzed self.locations = {} # informations about the location of a char @@ -65,7 +69,7 @@ def addFile(self, path): lines = None content = "" filename = os.path.basename(path) - roomname = filename[:-20] + roomname = filename[:-20].lower() try: with open(path, "r", encoding='utf-16-le') as f: content = f.read() @@ -103,6 +107,9 @@ def _lineToMessage(self, line, roomname): timestamp = datetime.datetime.strptime(timeStr, "%Y.%m.%d %H:%M:%S") except ValueError: return None + if (evegate.currentEveTime() - timestamp).total_seconds() > self.messageExpirySecs: + # logging.debug('ignoring message from ' + timeStr + " || " + str((evegate.currentEveTime() - timestamp).total_seconds()) ) + return None # finding the username of the poster userEnds = line.find(">") username = line[timeEnds + 1:userEnds].strip() @@ -136,7 +143,7 @@ def _lineToMessage(self, line, roomname): continue while parseUrls(rtext): continue - while parseSystems(self.systems, rtext, systems): + while parseSystems(self.allSystems, rtext, systems): continue parsedStatus = parseStatus(rtext) status = parsedStatus if parsedStatus is not None else states.ALARM @@ -154,9 +161,6 @@ def _lineToMessage(self, line, roomname): message.message = six.text_type(rtext) message.status = status self.knownMessages.append(message) - if systems: - for system in systems: - system.messages.append(message) return message def _parseLocal(self, path, line): @@ -202,14 +206,12 @@ def fileModified(self, path): # EvE names the file like room_20140913_200737.txt, so we don't need # the last 20 chars filename = os.path.basename(path) - roomname = filename[:-20] + roomname = filename[:-20].lower() if path not in self.fileData: # seems eve created a new file. New Files have 12 lines header - self.fileData[path] = {"lines": 13} + self.fileData[path] = {"lines": self.HEADER_SIZE()} oldLength = self.fileData[path]["lines"] lines = self.addFile(path) - if path in self.ignoredPaths: - return [] for line in lines[oldLength - 1:]: line = line.strip() if len(line) > 2: @@ -222,6 +224,22 @@ def fileModified(self, path): messages.append(message) return messages + def rewind(self): + """On region change or startup, rewind files to replay info from logfiles""" + for path in self.fileData: + newsize = self.fileData[path]["lines"] - self.REPLAY_SIZE() + if newsize < self.HEADER_SIZE(): + newsize = self.HEADER_SIZE() + logging.info("Rewinding %d lines from %s" % (self.fileData[path]["lines"]-newsize, path)) + self.fileData[path]["lines"] = newsize + return self.fileData + + def expire(self): + for m in self.knownMessages: + if (evegate.currentEveTime() - m.timestamp).total_seconds() > self.messageExpirySecs: + self.knownMessages.pop(0) + else: + break class Message(object): def __init__(self, room, message, timestamp, user, systems, upperText, plainText="", status=states.ALARM): @@ -235,6 +253,7 @@ def __init__(self, room, message, timestamp, user, systems, upperText, plainText self.plainText = plainText # plain text of the message, as posted # if you add the message to a widget, please add it to widgets self.widgets = [] + self.isOld = False def __key(self): return (self.room, self.plainText, self.timestamp, self.user) diff --git a/src/vi/chatparser/parser_functions.py b/src/vi/chatparser/parser_functions.py index 5ad171c..d9d38f9 100644 --- a/src/vi/chatparser/parser_functions.py +++ b/src/vi/chatparser/parser_functions.py @@ -36,13 +36,20 @@ """ import six +import logging +import re import vi.evegate as evegate from bs4 import BeautifulSoup from bs4.element import NavigableString from vi import states +from vi.systems import SYSTEMS -CHARS_TO_IGNORE = ("*", "?", ",", "!", ".") +# Do not ignore <>/" which keep html from word matching on replacement +# Do not ignore ? which triggers status change to request +CHARS_TO_IGNORE_REGEX = '[*,!.()]' + +REPLACE_WORD_REGEX = r'(^|(?<=[^0-9a-zA-Z])){0}((?=[^0-9a-zA-Z_])|$)' def textReplace(element, newText): @@ -58,39 +65,41 @@ def textReplace(element, newText): def parseStatus(rtext): texts = [t for t in rtext.contents if isinstance(t, NavigableString)] for text in texts: + upperText = re.sub(CHARS_TO_IGNORE_REGEX, ' ', text.strip().upper()) # KEEP QUESTION MARK? upperText = text.strip().upper() - originalText = upperText - for char in CHARS_TO_IGNORE: - upperText = upperText.replace(char, "") upperWords = upperText.split() - if (("CLEAR" in upperWords or "CLR" in upperWords) and not originalText.endswith("?")): + if ("?" in upperText): + return states.REQUEST + elif ("CLEAR" in upperWords or "CLR" in upperWords): return states.CLEAR elif ("STAT" in upperWords or "STATUS" in upperWords): return states.REQUEST - elif ("?" in originalText): - return states.REQUEST elif (text.strip().upper() in ("BLUE", "BLUES ONLY", "ONLY BLUE" "STILL BLUE", "ALL BLUES")): return states.CLEAR def parseShips(rtext): def formatShipName(text, word): - newText = u""" {0}""" - text = text.replace(word, newText.format(word)) + newText = u"""{0}""" + # Only do replacements at word boundaries + text = re.sub(REPLACE_WORD_REGEX.format(word), newText.format(word), text) return text texts = [t for t in rtext.contents if isinstance(t, NavigableString)] for text in texts: + upperText = re.sub(CHARS_TO_IGNORE_REGEX, ' ', text.upper()) upperText = text.upper() for shipName in evegate.SHIPNAMES: if shipName in upperText: hit = True start = upperText.find(shipName) end = start + len(shipName) - if ((start > 0 and upperText[start - 1] not in (" ", "X")) or ( - end < len(upperText) - 1 and upperText[end] not in ("S", " "))): + if ( (start > 0 and re.match('[A-Z0-9]', upperText[start - 1])) + or (end < len(upperText) and re.match('[A-RT-Z0-9]', upperText[end])) ): hit = False if hit: + if (end < len(upperText) and 'S' == upperText[end]): + end += 1 shipInText = text[start:end] formatted = formatShipName(text, shipInText) textReplace(text, formatted) @@ -98,29 +107,32 @@ def formatShipName(text, word): def parseSystems(systems, rtext, foundSystems): - + systemNames = systems.keys() - + # words to ignore on the system parser. use UPPER CASE - WORDS_TO_IGNORE = ("IN", "IS", "AS") + WORDS_TO_IGNORE = ("IN", "IS", "AS", "OR", "NV", "TO", "ME", "HE", "SHE", "YOU", "ARE", + "ON", "HAS", "OF", "IT", "GET", "IF", "THE", "HOT", "OH", "OK", "GJ", "AND", "MY", + "SAY", "ANY", "NO", "FOR", "OUT", "WH", "MAN", "PART", "AT", "AN" ) def formatSystem(text, word, system): newText = u"""{1}""" - text = text.replace(word, newText.format(system, word)) + # Only do replacements at word boundaries: "no cyno onboard" would replace both "no"s in the first pass and then find a "cy" + text = re.sub(REPLACE_WORD_REGEX.format(word), newText.format(system, word), text) return text - texts = [t for t in rtext.contents if isinstance(t, NavigableString) and len(t)] - for wtIdx, text in enumerate(texts): - worktext = text - for char in CHARS_TO_IGNORE: - worktext = worktext.replace(char, "") - + texts = [t for t in rtext.contents if isinstance(t, NavigableString) and len(t)] + for text in texts: + worktext = re.sub(CHARS_TO_IGNORE_REGEX, ' ', text) + # Drop redundant whitespace so as to not throw off word index worktext = ' '.join(worktext.split()) words = worktext.split(" ") for idx, word in enumerate(words): - + + matchKey = None + # Is this about another a system's gate? if len(words) > idx + 1: if words[idx+1].upper() == 'GATE': @@ -133,42 +145,22 @@ def formatSystem(text, word, system): # '_____ GATE' mentioned in message, which is not what we're # interested in, so go to checking next word. continue - + upperWord = word.upper() if upperWord != word and upperWord in WORDS_TO_IGNORE: continue if upperWord in systemNames: # - direct hit on name - foundSystems.add(systems[upperWord]) # of the system? - formattedText = formatSystem(text, word, upperWord) - textReplace(text, formattedText) - return True - elif 1 < len(upperWord) < 5: # - upperWord < 4 chars. + matchKey = systems[upperWord]['name'] + elif 1 < len(upperWord) < 5: # - upperWord 2-4 chars. for system in systemNames: # system begins with? if system.startswith(upperWord): - foundSystems.add(systems[system]) - formattedText = formatSystem(text, word, system) - textReplace(text, formattedText) - return True - elif "-" in upperWord and len(upperWord) > 2: # - short with - (minus) - upperWordParts = upperWord.split("-") # (I-I will match I43-IF3) - for system in systemNames: - systemParts = system.split("-") - if (len(upperWordParts) == 2 and len(systemParts) == 2 and len(upperWordParts[0]) > 1 and len( - upperWordParts[1]) > 1 and len(systemParts[0]) > 1 and len(systemParts[1]) > 1 and len( - upperWordParts) == len(systemParts) and upperWordParts[0][0] == systemParts[0][0] and - upperWordParts[1][0] == systemParts[1][0]): - foundSystems.add(systems[system]) - formattedText = formatSystem(text, word, system) - textReplace(text, formattedText) - return True - elif len(upperWord) > 1: # what if F-YH58 is named FY? - for system in systemNames: - clearedSystem = system.replace("-", "") - if clearedSystem.startswith(upperWord): - foundSystems.add(systems[system]) - formattedText = formatSystem(text, word, system) - textReplace(text, formattedText) - return True - + matchKey = systems[system]['name'] + break + if matchKey: + foundSystems.add(matchKey) + formattedText = formatSystem(text, word, matchKey) + textReplace(text, formattedText) + return True + return False diff --git a/src/vi/dotlan.py b/src/vi/dotlan.py index 182b7bd..1d41038 100644 --- a/src/vi/dotlan.py +++ b/src/vi/dotlan.py @@ -23,6 +23,7 @@ import math import time +import datetime import six import requests import logging @@ -37,7 +38,6 @@ "88aa00" "FFE4E1", "008080", "00BFFF", "4682B4", "00FF7F", "7FFF00", "ff6600", "CD5C5C", "FFD700", "66CDAA", "AFEEEE", "5F9EA0", "FFDEAD", "696969", "2F4F4F") - class DotlanException(Exception): def __init__(self, *args, **kwargs): Exception.__init__(self, *args, **kwargs) @@ -48,8 +48,6 @@ class Map(object): The map including all information from dotlan """ - DOTLAN_BASIC_URL = u"http://evemaps.dotlan.net/svg/{0}.svg" - @property def svg(self): # Re-render all systems @@ -90,17 +88,40 @@ def __init__(self, region, svgFile=None): "without the map.\n\nRemember the site for possible " \ "updates: https://github.com/Xanthos-Eve/vintel".format(type(e), six.text_type(e)) raise DotlanException(t) + # Create soup from the svg - self.soup = BeautifulSoup(svg, 'html.parser') - self.systems = self._extractSystemsFromSoup(self.soup) - self.systemsById = {} - for system in self.systems.values(): - self.systemsById[system.systemId] = system - self._prepareSvg(self.soup, self.systems) - self._connectNeighbours() - self._jumpMapsVisible = False - self._statisticsVisible = False - self.marker = self.soup.select("#select_marker")[0] + try: + self.soup = BeautifulSoup(svg, 'html.parser') + self.systems = self._extractSystemsFromSoup(self.soup) + self._cleanSoup(self.soup) + self.setJumpbridgesVisibility(False) + self.systemsById = {} + for system in self.systems.values(): + self.systemsById[system.systemId] = system + self._prepareSvg(self.soup, self.systems) + self._connectNeighbours() + self._jumpMapsVisible = False + self._statisticsVisible = False + self.marker = self.soup.select("#select_marker")[0] + except Exception as e: + # Could get hung up on a bad retreival forever + cache.deleteFromCache("map_" + self.region) + raise + + def _cleanSoup(self, soup): + try: + legend = soup.find('g', id='legend') + copyright = legend.find('text', class_='lc') + copyright.string = '(C) by Wollari & CCP' + for t in legend.select("text"): + if t.text == '= Alliance': + t.string = '= Intel Time' + elif t.text == '= Sov. Lvl' or t.text == 'Z': + t.string = '' + elif t.text == 'YYYYY (Z)': + t.string = 'YYYYY' + except: + pass def _extractSystemsFromSoup(self, soup): systems = {} @@ -118,16 +139,21 @@ def _extractSystemsFromSoup(self, soup): continue for element in symbol.select(".sys"): name = element.select("text")[0].text.strip().upper() + # could be region name or sov. info + secondaryInfo = element.select("text")[1].text.strip().upper() mapCoordinates = {} for keyname in ("x", "y", "width", "height"): mapCoordinates[keyname] = float(uses[symbolId][keyname]) mapCoordinates["center_x"] = (mapCoordinates["x"] + (mapCoordinates["width"] / 2)) mapCoordinates["center_y"] = (mapCoordinates["y"] + (mapCoordinates["height"] / 2)) + # Modify href to just be system name to deal better with out of region systems drawn on map + # leaving slash for now, not sure about effects on provi/catch combined maps + symbol.a['xlink:href'] = "/" + name try: transform = uses[symbolId]["transform"] except KeyError: transform = "translate(0,0)" - systems[name] = System(name, element, self.soup, mapCoordinates, transform, systemId) + systems[name] = System(name, secondaryInfo, element, self.soup, mapCoordinates, transform, systemId) return systems def _prepareSvg(self, soup, systems): @@ -191,7 +217,7 @@ def _connectNeighbours(self): startSystem.addNeighbour(stopSystem) def _getSvgFromDotlan(self, region): - url = self.DOTLAN_BASIC_URL.format(region) + url = dotlan_url(region) content = requests.get(url).text return content @@ -263,7 +289,15 @@ def changeStatisticsVisibility(self): def changeJumpbridgesVisibility(self): newStatus = False if self._jumpMapsVisible else True + return self.setJumpbridgesVisibility(newStatus) + + def setJumpbridgesVisibility(self, newStatus): value = "visible" if newStatus else "hidden" + try: + for jb in self.soup.select('path.jb'): + jb['visibility'] = value + except: + pass for line in self.soup.select(".jumpbridge"): line["visibility"] = value self._jumpMapsVisible = newStatus @@ -285,25 +319,32 @@ class System(object): A System on the Map """ - ALARM_COLORS = [(60 * 4, "#FF0000", "#FFFFFF"), (60 * 10, "#FF9B0F", "#FFFFFF"), (60 * 15, "#FFFA0F", "#000000"), - (60 * 25, "#FFFDA2", "#000000"), (60 * 60 * 24, "#FFFFFF", "#000000")] - ALARM_COLOR = ALARM_COLORS[0][1] UNKNOWN_COLOR = "#FFFFFF" CLEAR_COLOR = "#59FF6C" - - def __init__(self, name, svgElement, mapSoup, mapCoordinates, transform, systemId): + ALARM_COLORS = [ + # Alarmed systems change colors based on how long ago the alarm was received + # maxDiff (seconds), system background color, timer text color + (60 * 4, "#FF0000", "#FFFFFF"), + (60 * 10, "#FF9B0F", "#FFFFFF"), + (60 * 15, "#FFFA0F", "#000000"), + (60 * 25, "#FFFDA2", "#000000"), + (60 * 60 * 24, "#FFFFFF", "#000000") + ] + + def __init__(self, name, secondaryInfo, svgElement, mapSoup, mapCoordinates, transform, systemId): self.status = states.UNKNOWN self.name = name + self.secondaryInfo = secondaryInfo self.svgElement = svgElement self.mapSoup = mapSoup self.origSvgElement = svgElement self.rect = svgElement.select("rect")[0] self.secondLine = svgElement.select("text")[1] - self.lastAlarmTime = 0 + self.lastAlarmTime = datetime.datetime.min self.messages = [] self.setStatus(states.UNKNOWN) self.__locatedCharacters = [] - self.backgroundColor = "#FFFFFF" + self.backgroundColor = self.UNKNOWN_COLOR self.mapCoordinates = mapCoordinates self.systemId = systemId self.transform = transform @@ -418,16 +459,22 @@ def removeNeighbour(self, system): if self in system._neighbours: system._neigbours.remove(self) - def setStatus(self, newStatus): + def setStatus(self, newStatus, statusTime = None): + if None == statusTime: + statusTime = evegate.currentEveTime() if newStatus == states.ALARM: - self.lastAlarmTime = time.time() + self.lastAlarmTime = statusTime if "stopwatch" not in self.secondLine["class"]: self.secondLine["class"].append("stopwatch") self.secondLine["alarmtime"] = self.lastAlarmTime self.secondLine["style"] = "fill: #FFFFFF;" - self.setBackgroundColor(self.ALARM_COLOR) + delta = (evegate.currentEveTime() - self.lastAlarmTime).total_seconds() + for maxDiff, alarmColor, secondLineColor in self.ALARM_COLORS: + if delta < maxDiff: + self.setBackgroundColor(alarmColor) + break elif newStatus == states.CLEAR: - self.lastAlarmTime = time.time() + self.lastAlarmTime = statusTime self.setBackgroundColor(self.CLEAR_COLOR) self.secondLine["alarmtime"] = 0 if "stopwatch" not in self.secondLine["class"]: @@ -457,7 +504,7 @@ def setStatistics(self, statistics): def update(self): # state changed? if (self.status == states.ALARM): - alarmTime = time.time() - self.lastAlarmTime + alarmTime = (evegate.currentEveTime() - self.lastAlarmTime).total_seconds() for maxDiff, alarmColor, secondLineColor in self.ALARM_COLORS: if alarmTime < maxDiff: if self.backgroundColor != alarmColor: @@ -468,7 +515,7 @@ def update(self): self.secondLine["style"] = "fill: {0};".format(secondLineColor) break if self.status in (states.ALARM, states.WAS_ALARMED, states.CLEAR): # timer - diff = math.floor(time.time() - self.lastAlarmTime) + diff = (evegate.currentEveTime() - self.lastAlarmTime).total_seconds() minutes = int(math.floor(diff / 60)) seconds = int(diff - minutes * 60) string = "{m:02d}:{s:02d}".format(m=minutes, s=seconds) @@ -483,9 +530,18 @@ def update(self): self.secondLine.string = string +def dotlan_url(region): + """ Generate a DOTLAN url from the specified region name (which will be normalized to a DOTLAN region name) + """ + url = u"http://evemaps.dotlan.net/svg/{0}.svg".format(convertRegionName(region)) + jb_id = Cache().getConfigValue("dotlan_jb_id") + if jb_id: + url = url + u"?path=B:{0}".format(jb_id) + return url + def convertRegionName(name): """ - Converts a (system)name to the format that dotland uses + Converts a (system)name to the format that dotlan uses """ converted = [] nextUpper = False diff --git a/src/vi/evegate.py b/src/vi/evegate.py index c0a4b16..0cef94b 100644 --- a/src/vi/evegate.py +++ b/src/vi/evegate.py @@ -33,19 +33,28 @@ NOT_EXISTS = 0 EXISTS = 1 +def esi_post(uri, data): + try: + url = 'https://esi.evetech.net/latest' + uri + '/?datasource=tranquility&language=en-us' + return requests.post(url, data=json.dumps(data), headers={'accept': 'application/json', 'Content-Type': 'application/json'}) + except Exception as e: + logging.error('ESI POST FAILED URI: [%s] data: [%s]' % (uri, repr(data))) + +def esi_get(uri, **kwargs): + try: + url = 'https://esi.evetech.net/latest' + uri + '/?datasource=tranquility&language=en-us' + if 'query' in kwargs: + url += '&' + kwargs['query'] + return requests.get(url, headers={'accept': 'application/json', 'Content-Type': 'application/json'}) + except Exception as e: + logging.error('ESI GET FAILED URI: [%s] data: [%s]' % (uri)) def charnameToId(name): """ Uses the EVE API to convert a charname to his ID """ try: - url = "https://api.eveonline.com/eve/CharacterID.xml.aspx" - content = requests.get(url, params={'names': name}).text - soup = BeautifulSoup(content, 'html.parser') - rowSet = soup.select("rowset")[0] - for row in rowSet.select("row"): - if row["name"] == name: - return int(row["characterid"]) - + content = esi_post('/universe/ids', [name]).json() + return int(content['characters'][0]['id']) except Exception as e: logging.error("Exception turning charname to id via API: %s", e) # fallback! if there is a problem with the API, we use evegate @@ -81,16 +90,13 @@ def namesToIds(names): try: # not in cache? asking the EVE API if len(apiCheckNames) > 0: - url = "https://api.eveonline.com/eve/CharacterID.xml.aspx" - content = requests.get(url, params={'names': ','.join(apiCheckNames)}).text - soup = BeautifulSoup(content, 'html.parser') - rowSet = soup.select("rowset")[0] - for row in rowSet.select("row"): - data[row["name"]] = row["characterid"] + response = esi_post('/universe/ids', apiCheckNames).json() + for row in response.json()['characters']: + data[row["name"]] = row['id'] # writing the cache for name in apiCheckNames: cacheKey = "_".join(("id", "name", name)) - cache.putIntoCache(cacheKey, data[name], 60 * 60 * 24 * 365) + cache.putIntoCache(cacheKey, data[name], cache.PERMANENT) except Exception as e: logging.error("Exception during namesToIds: %s", e) return data @@ -118,17 +124,14 @@ def idsToNames(ids): try: # call the EVE-Api for those entries we didn't have in the cache - url = "https://api.eveonline.com/eve/CharacterName.xml.aspx" if len(apiCheckIds) > 0: - content = requests.get(url, params={'ids': ','.join(apiCheckIds)}).text - soup = BeautifulSoup(content, 'html.parser') - rowSet = soup.select("rowset")[0] - for row in rowSet.select("row"): - data[row["characterid"]] = row["name"] + response = esi_get('/characters/names', query=','.join(apiCheckIds)) + for row in response.json(): + data[row["character_id"]] = row["character_name"] # and writing into cache for id in apiCheckIds: cacheKey = u"_".join(("name", "id", six.text_type(id))) - cache.putIntoCache(cacheKey, data[id], 60 * 60 * 24 * 365) + cache.putIntoCache(cacheKey, data[id], cache.PERMANENT) except Exception as e: logging.error("Exception during idsToNames: %s", e) @@ -152,27 +155,6 @@ def getAvatarForPlayer(charname): return avatar -def checkPlayername(charname): - """ Checking on evegate for an exiting playername - returns 1 if exists, 0 if not and -1 if an error occured - """ - baseUrl = "https://gate.eveonline.com/Profile/" - - queryCharname = requests.utils.quote(charname) - url = baseUrl + queryCharname - result = -1 - - try: - urlopen(url) - result = 1 - except HTTPError as e: - if ("404") in str(e): - result = 0 - except Exception as e: - logging.error("Exception on checkPlayername: %s", e) - return result - - def currentEveTime(): """ Returns the current eve-time as a datetime.datetime """ @@ -185,37 +167,21 @@ def eveEpoch(): return time.mktime(datetime.datetime.utcnow().timetuple()) -def getCharinfoForCharId(charId): - cacheKey = u"_".join(("playerinfo_id_", six.text_type(charId))) - cache = Cache() - soup = cache.getFromCache(cacheKey) - if soup is not None: - soup = BeautifulSoup(soup, 'html.parser') - else: - try: - charId = int(charId) - url = "https://api.eveonline.com/eve/CharacterInfo.xml.aspx" - content = requests.get(url, params={'characterID': charId}).text - soup = BeautifulSoup(content, 'html.parser') - cacheUntil = datetime.datetime.strptime(soup.select("cacheduntil")[0].text, "%Y-%m-%d %H:%M:%S") - diff = cacheUntil - currentEveTime() - cache.putIntoCache(cacheKey, str(soup), diff.seconds) - except requests.exceptions.RequestException as e: - # We get a 400 when we pass non-pilot names for KOS check so fail silently for that one only - if (e.response.status_code != 400): - logging.error("Exception during getCharinfoForCharId: %s", str(e)) - return soup - - def getCorpidsForCharId(charId): """ Returns a list with the ids if the corporation history of a charId """ + cacheKey = u"_".join(("playerinfo_id_", six.text_type(charId))) + cache = Cache() + data = cache.getFromCache(cacheKey) + if data: + return data + data = [] - soup = getCharinfoForCharId(charId) - for rowSet in soup.select("rowset"): - if rowSet["name"] == "employmentHistory": - for row in rowSet.select("row"): - data.append(row["corporationid"]) + response = esi_get('/characters/%s/corporationhistory' % (charId)) + for row in response.json(): + data.append(row["corporation_id"]) + + cache.putIntoCache(cacheKey, data, cache.ONE_DAY) return data @@ -234,15 +200,11 @@ def getSystemStatistics(): try: if jumpData is None: jumpData = {} - url = "https://api.eveonline.com/map/Jumps.xml.aspx" - content = requests.get(url).text - soup = BeautifulSoup(content, 'html.parser') - - for result in soup.select("result"): - for row in result.select("row"): - jumpData[int(row["solarsystemid"])] = int(row["shipjumps"]) + response = esi_get("/universe/system_jumps") + for row in response.json(): + jumpData[int(row["system_id"])] = int(row["ship_jumps"]) - cacheUntil = datetime.datetime.strptime(soup.select("cacheduntil")[0].text, "%Y-%m-%d %H:%M:%S") + cacheUntil = datetime.datetime.strptime(response.headers['expires'], '%a, %d %b %Y %H:%M:%S GMT') diff = cacheUntil - currentEveTime() cache.putIntoCache(cacheKey, json.dumps(jumpData), diff.seconds) else: @@ -254,17 +216,13 @@ def getSystemStatistics(): if systemData is None: systemData = {} - url = "https://api.eveonline.com/map/Kills.xml.aspx" - content = requests.get(url).text - soup = BeautifulSoup(content, 'html.parser') - - for result in soup.select("result"): - for row in result.select("row"): - systemData[int(row["solarsystemid"])] = {"ship": int(row["shipkills"]), - "faction": int(row["factionkills"]), - "pod": int(row["podkills"])} + response = esi_get("/universe/system_kills") + for row in response.json(): + systemData[int(row["system_id"])] = {"ship": int(row["ship_kills"]), + "faction": int(row["npc_kills"]), + "pod": int(row["pod_kills"])} - cacheUntil = datetime.datetime.strptime(soup.select("cacheduntil")[0].text, "%Y-%m-%d %H:%M:%S") + cacheUntil = datetime.datetime.strptime(response.headers['expires'], '%a, %d %b %Y %H:%M:%S GMT') diff = cacheUntil - currentEveTime() cache.putIntoCache(cacheKey, json.dumps(systemData), diff.seconds) else: @@ -312,7 +270,7 @@ def secondsTillDowntime(): u'CERBERUS', u'CHARON', u'CHEETAH', u'CHIMERA', u'CLAW', u'CLAYMORE', u'COERCER', u'CONDOR', u'CORMORANT', u'COVETOR', u'CRANE', u'CROW', u'CRUCIFIER', u'CRUOR', u'CRUSADER', u'CURSE', u'CYCLONE', u'CYNABAL', u'DAMNATION', u'DAREDEVIL', u'DEIMOS', u'DEVOTER', u'DOMINIX', u'DRAKE', u'DRAMIEL', u'EAGLE', u'EIDOLON', - u'ENIGMA', u'ENYO', u'EOS', u'EREBUS', u'ERIS', u'EXECUTIONER', u'EXEQUROR', u'EXEQUROR NAVY ISSUE', + u'ENDURANCE', u'ENIGMA', u'ENYO', u'EOS', u'EREBUS', u'ERIS', u'EXECUTIONER', u'EXEQUROR', u'EXEQUROR NAVY ISSUE', u'FALCON', u'FEDERATION NAVY COMET', u'FENRIR', u'FEROX', u'FLYCATCHER', u'GALLENTE SHUTTLE', u'GILA', u'GOLD MAGNATE', u'GOLEM', u'GRIFFIN', u'GUARDIAN', u'HARBINGER', u'HARPY', u'HAWK', u'HEL', u'HELIOS', u'HERETIC', u'HERON', u'HOARDER', u'HOUND', u'HUGINN', u'HULK', u'HURRICANE', u'HYENA', u'HYPERION', @@ -325,7 +283,8 @@ def secondsTillDowntime(): u'NOMAD', u'NYX', u'OBELISK', u'OCCATOR', u'OMEN', u'OMEN NAVY ISSUE', u'ONEIROS', u'ONYX', u'OPUX DRAGOON YACHT', u'OPUX LUXURY YACHT', u'ORACLE', u'ORCA', u'OSPREY', u'OSPREY NAVY ISSUE', u'PALADIN', u'PANTHER', u'PHANTASM', u'PHANTOM', u'PHOBOS', u'PHOENIX', u'PILGRIM', u'POLARIS CENTURION', - u'POLARIS INSPECTOR', u'POLARIS LEGATUS', u'PROBE', u'PROCURER', u'PROPHECY', u'PRORATOR', u'PROVIDENCE', + u'POLARIS INSPECTOR', u'POLARIS LEGATUS', u'PORPOISE', u'PROBE', u'PROCURER', u'PROPHECY', u'PRORATOR', + u'PROSPECT', u'PROVIDENCE', u'PROWLER', u'PUNISHER', u'PURIFIER', u'RAGNAROK', u'RAPIER', u'RAPTOR', u'RATTLESNAKE', u'RAVEN', u'RAVEN NAVY ISSUE', u'RAVEN STATE ISSUE', u'REAPER', u'REDEEMER', u'REPUBLIC FLEET FIRETAIL', u'RETRIBUTION', u'RETRIEVER', u'REVELATION', u'RHEA', u'RIFTER', u'ROKH', u'ROOK', u'RORQUAL', u'RUPTURE', @@ -335,7 +294,11 @@ def secondsTillDowntime(): u'TEMPEST TRIBAL ISSUE', u'THANATOS', u'THORAX', u'THRASHER', u'TORMENTOR', u'TRISTAN', u'TYPHOON', u'VAGABOND', u'VARGUR', u'VELATOR', u'VENGEANCE', u'VEXOR', u'VEXOR NAVY ISSUE', u'VIATOR', u'VIGIL', u'VIGILANT', u'VINDICATOR', u'VISITANT', u'VULTURE', u'WIDOW', u'WOLF', u'WORM', u'WRAITH', u'WREATHE', - u'WYVERN', u'ZEALOT', u'CAPSULE',) + u'WYVERN', u'ZEALOT', u'CAPSULE', + u'BOMBER', u'LOGI', + u'T3D', u'JACKDAW', u'SVIPUL', u'CONFESSOR', u'HECTATE', + u'T3C', u'TENGU', u'LOKI', u'LEGION', u'PROTEUS', + u'STORK', u'BIFROST', u'PONTIFEX', u'MAGUS') SHIPNAMES = sorted(SHIPNAMES, key=lambda x: len(x), reverse=True) NPC_CORPS = (u'Republic Justice Department', u'House of Records', u'24th Imperial Crusade', u'Template:NPC corporation', diff --git a/src/vi/koschecker.py b/src/vi/koschecker.py index 0296ecd..52ef797 100644 --- a/src/vi/koschecker.py +++ b/src/vi/koschecker.py @@ -36,8 +36,12 @@ def check(parts): namesAsIds = {} names = [name.strip() for name in parts] + kos_url = Cache().getConfigValue("kos_url") + if not kos_url: + kos_url = CVA_KOS_URL + try: - kosData = requests.get(CVA_KOS_URL, params = {'c': 'json', 'type': 'multi', 'q': ','.join(names)}).json() + kosData = requests.get(kos_url, params = {'c': 'json', 'type': 'multi', 'q': ','.join(names)}).json() except RequestException as e: kosData = None logging.error("Error on pilot KOS check request %s", str(e)) @@ -95,7 +99,7 @@ def check(parts): for corp in corpsToCheck: try: - kosData = requests.get(CVA_KOS_URL, params = { 'c': 'json', 'type': 'unit', 'q': corp }).json() + kosData = requests.get(kos_url, params = { 'c': 'json', 'type': 'unit', 'q': corp }).json() except RequestException as e: logging.error("Error on corp KOS check request: %s", str(e)) diff --git a/src/vi/regions.py b/src/vi/regions.py new file mode 100644 index 0000000..9c4fd1b --- /dev/null +++ b/src/vi/regions.py @@ -0,0 +1,66 @@ +REGIONS = [ + "Aridia", + "Black Rise", + "Branch", + "Cache", + "Catch", + "Cloud Ring", + "Cobalt Edge", + "Curse", + "Deklein", + "Delve", + "Derelik", + "Detorid", + "Devoid", + "Domain", + "Esoteria", + "Essence", + "Etherium Reach", + "Everyshore", + "Fade", + "Feythabolis", + "Fountain", + "Geminate", + "Genesis", + "Great Wildlands", + "Heimatar", + "Immensea", + "Impass", + "Insmother", + "Kador", + "Khanid", + "Kor-Azor", + "Lonetrek", + "Malpais", + "Metropolis", + "Molden Heath", + "Oasa", + "Omist", + "Outer Passage", + "Outer Ring", + "Paragon Soul", + "Period Basis", + "Perrigen Falls", + "Placid", + "Providence", + "Pure Blind", + "Querious", + "Scalding Pass", + "Sinq Laison", + "Solitude", + "Stain", + "Syndicate", + "Tash-Murkon", + "Tenal", + "Tenerifis", + "The Bleak Lands", + "The Citadel", + "The Forge", + "The Kalevala Expanse", + "The Spire", + "Tribute", + "Vale of the Silent", + "Venal", + "Verge Vendor", + "Wicked Creek" +] diff --git a/src/vi/states.py b/src/vi/states.py index 202ea0c..ac3c3c5 100644 --- a/src/vi/states.py +++ b/src/vi/states.py @@ -26,7 +26,7 @@ NOT_CHANGE = 'no change' CLEAR = 'clear' ALARM = 'alarm' -WAS_ALARMED = 'was alarmed' +WAS_ALARMED = 'was alarmed' # UNUSED REQUEST = 'request' LOCATION = 'location' KOS_STATUS_REQUEST = 'kos request' diff --git a/src/vi/systems.py b/src/vi/systems.py new file mode 100644 index 0000000..df6adcc --- /dev/null +++ b/src/vi/systems.py @@ -0,0 +1,5465 @@ +SYSTEMS = { + "Tanoo": "Derelik", + "Lashesih": "Derelik", + "Akpivem": "Derelik", + "Jark": "Derelik", + "Sasta": "Derelik", + "Zaid": "Derelik", + "Yuzier": "Derelik", + "Nirbhi": "Derelik", + "Sooma": "Derelik", + "Chidah": "Derelik", + "Shenela": "Derelik", + "Asabona": "Derelik", + "Onsooh": "Derelik", + "Shamahi": "Derelik", + "Sendaya": "Derelik", + "Nazhgete": "Derelik", + "Futzchag": "Derelik", + "Kazna": "Derelik", + "Podion": "Derelik", + "Lilmad": "Derelik", + "Kuharah": "Derelik", + "Jayneleb": "Derelik", + "Fovihi": "Derelik", + "Kiereend": "Derelik", + "Rashy": "Derelik", + "Ordize": "Derelik", + "Psasa": "Derelik", + "Eshtah": "Derelik", + "Lachailes": "Derelik", + "Kasrasi": "Derelik", + "Mohas": "Derelik", + "Hasiari": "Derelik", + "Radima": "Derelik", + "Alkez": "Derelik", + "Nimambal": "Derelik", + "Yishinoon": "Derelik", + "Uplingur": "Derelik", + "Dooz": "Derelik", + "Bayuka": "Derelik", + "Uzistoon": "Derelik", + "Bairshir": "Derelik", + "Moh": "Derelik", + "Sari": "Derelik", + "Faspera": "Derelik", + "Jaymass": "Derelik", + "Mifrata": "Derelik", + "Majamar": "Derelik", + "Ihal": "Derelik", + "Camal": "Derelik", + "Fera": "Derelik", + "Juddi": "Derelik", + "Maspah": "Derelik", + "Ibaria": "Derelik", + "Shala": "Derelik", + "Zemalu": "Derelik", + "Khankenirdia": "Derelik", + "Nikh": "Derelik", + "Amphar": "Derelik", + "Salashayama": "Derelik", + "Janus": "Derelik", + "Agha": "Derelik", + "Iosantin": "Derelik", + "Orva": "Derelik", + "Zet": "Derelik", + "Akhrad": "Derelik", + "Pirohdim": "Derelik", + "Sharir": "Derelik", + "Usroh": "Derelik", + "Thiarer": "Derelik", + "Gomati": "Derelik", + "Jangar": "Derelik", + "Nakah": "Derelik", + "Irshah": "Derelik", + "Hasateem": "Derelik", + "Assah": "Derelik", + "Tidacha": "Derelik", + "Odlib": "Derelik", + "Jofan": "Derelik", + "Milu": "Derelik", + "Yadi": "Derelik", + "Buftiar": "Derelik", + "Jarizza": "Derelik", + "Ejahi": "Derelik", + "Asghatil": "Derelik", + "Bar": "Derelik", + "Sucha": "Derelik", + "Gelhan": "Derelik", + "Akeva": "Derelik", + "Sosa": "Derelik", + "Ilahed": "Derelik", + "Eshwil": "Derelik", + "Aranir": "Derelik", + "Ishkad": "Derelik", + "Hahyil": "Derelik", + "Asilem": "Derelik", + "Mahnagh": "Derelik", + "Shach": "Derelik", + "Kehrara": "Derelik", + "Arena": "Derelik", + "Timeor": "Derelik", + "Uhtafal": "Derelik", + "Dysa": "Derelik", + "Serad": "Derelik", + "Mahti": "Derelik", + "Abha": "Derelik", + "Shedoo": "Derelik", + "Gamis": "Derelik", + "Nieril": "Derelik", + "Berta": "Derelik", + "Bekirdod": "Derelik", + "Hothomouh": "Derelik", + "Arnola": "Derelik", + "Astabih": "Derelik", + "Ubtes": "Derelik", + "Bimener": "Derelik", + "Kenobanala": "Derelik", + "Khabi": "Derelik", + "Uanzin": "Derelik", + "Itamo": "The Forge", + "Mitsolen": "The Forge", + "Jatate": "The Forge", + "Mahtista": "The Forge", + "Vaankalen": "The Forge", + "Kylmabe": "The Forge", + "Ahtulaima": "The Forge", + "Geras": "The Forge", + "Sirseshin": "The Forge", + "Tuuriainas": "The Forge", + "Unpas": "The Forge", + "Shihuken": "The Forge", + "Nomaa": "The Forge", + "Ansila": "The Forge", + "Hirtamon": "The Forge", + "Hykkota": "The Forge", + "Outuni": "The Forge", + "Ohmahailen": "The Forge", + "Eskunen": "The Forge", + "Ikuchi": "The Forge", + "Urlen": "The Forge", + "Maurasi": "The Forge", + "Kisogo": "The Forge", + "Jita": "The Forge", + "Niyabainen": "The Forge", + "Perimeter": "The Forge", + "New Caldari": "The Forge", + "Saisio": "The Forge", + "Abagawa": "The Forge", + "Jakanerva": "The Forge", + "Gekutami": "The Forge", + "Hurtoken": "The Forge", + "Uoyonen": "The Forge", + "Hampinen": "The Forge", + "Poinen": "The Forge", + "Liekuri": "The Forge", + "Obanen": "The Forge", + "Josameto": "The Forge", + "Otela": "The Forge", + "Olo": "The Forge", + "Ikami": "The Forge", + "Reisen": "The Forge", + "Purjola": "The Forge", + "Maila": "The Forge", + "Akora": "The Forge", + "Messoya": "The Forge", + "Ishisomo": "The Forge", + "Airmia": "The Forge", + "Sakkikainen": "The Forge", + "Friggi": "The Forge", + "Ihakana": "The Forge", + "Vahunomi": "The Forge", + "Otitoh": "The Forge", + "Otomainen": "The Forge", + "Vattuolen": "The Forge", + "Onuse": "The Forge", + "Soshin": "The Forge", + "Keikaken": "The Forge", + "Ukkalen": "The Forge", + "Akkilen": "The Forge", + "Silen": "The Forge", + "Osmon": "The Forge", + "Korsiki": "The Forge", + "Inaya": "The Forge", + "Nuken": "The Forge", + "Uminas": "The Forge", + "Airaken": "The Forge", + "Oijanen": "The Forge", + "Wuos": "The Forge", + "Hentogaira": "The Forge", + "Kiainti": "The Forge", + "Vasala": "The Forge", + "Walvalin": "The Forge", + "Otanuomi": "The Forge", + "Vouskiaho": "The Forge", + "Otsela": "The Forge", + "Tasti": "The Forge", + "Otosela": "The Forge", + "Uemon": "The Forge", + "Paala": "The Forge", + "Fuskunen": "The Forge", + "Akkio": "The Forge", + "Uchoshi": "The Forge", + "Mastakomon": "The Forge", + "Eruka": "The Forge", + "Ohkunen": "The Forge", + "Obe": "The Forge", + "Wirashoda": "The Forge", + "Osaa": "The Forge", + "Sakenta": "The Forge", + "Senda": "The Forge", + "Aokannitoh": "The Forge", + "Uitra": "The Forge", + "LZ-6SU": "Vale of the Silent", + "MC6O-F": "Vale of the Silent", + "U54-1L": "Vale of the Silent", + "B-588R": "Vale of the Silent", + "NCGR-Q": "Vale of the Silent", + "G-LOIT": "Vale of the Silent", + "HE-V4V": "Vale of the Silent", + "N-HSK0": "Vale of the Silent", + "05R-7A": "Vale of the Silent", + "7-UH4Z": "Vale of the Silent", + "5ZO-NZ": "Vale of the Silent", + "FS-RFL": "Vale of the Silent", + "Y0-BVN": "Vale of the Silent", + "X97D-W": "Vale of the Silent", + "0-R5TS": "Vale of the Silent", + "H-UCD1": "Vale of the Silent", + "7-K5EL": "Vale of the Silent", + "H-5GUI": "Vale of the Silent", + "FH-TTC": "Vale of the Silent", + "FMBR-8": "Vale of the Silent", + "3HX-DL": "Vale of the Silent", + "UH-9ZG": "Vale of the Silent", + "NFM-0V": "Vale of the Silent", + "YXIB-I": "Vale of the Silent", + "MY-T2P": "Vale of the Silent", + "FA-DMO": "Vale of the Silent", + "GEKJ-9": "Vale of the Silent", + "Q-R3GP": "Vale of the Silent", + "N-5QPW": "Vale of the Silent", + "XV-8JQ": "Vale of the Silent", + "WBR5-R": "Vale of the Silent", + "4GYV-Q": "Vale of the Silent", + "4-HWWF": "Vale of the Silent", + "YMJG-4": "Vale of the Silent", + "8TPX-N": "Vale of the Silent", + "PM-DWE": "Vale of the Silent", + "K8X-6B": "Vale of the Silent", + "X445-5": "Vale of the Silent", + "KRUN-N": "Vale of the Silent", + "9OO-LH": "Vale of the Silent", + "V-OJEN": "Vale of the Silent", + "EIDI-N": "Vale of the Silent", + "P3EN-E": "Vale of the Silent", + "49-0LI": "Vale of the Silent", + "IPAY-2": "Vale of the Silent", + "DAYP-G": "Vale of the Silent", + "IFJ-EL": "Vale of the Silent", + "47L-J4": "Vale of the Silent", + "Q-L07F": "Vale of the Silent", + "E-D0VZ": "Vale of the Silent", + "6WW-28": "Vale of the Silent", + "A8A-JN": "Vale of the Silent", + "S-NJBB": "Vale of the Silent", + "T-GCGL": "Vale of the Silent", + "0MV-4W": "Vale of the Silent", + "TVN-FM": "Vale of the Silent", + "V-NL3K": "Vale of the Silent", + "AZBR-2": "Vale of the Silent", + "Z-8Q65": "Vale of the Silent", + "0J3L-V": "Vale of the Silent", + "H-NOU5": "Vale of the Silent", + "KX-2UI": "Vale of the Silent", + "MO-FIF": "Vale of the Silent", + "97-M96": "Vale of the Silent", + "MA-XAP": "Vale of the Silent", + "C-J7CR": "Vale of the Silent", + "Q-EHMJ": "Vale of the Silent", + "XSQ-TF": "Vale of the Silent", + "H-1EOH": "Vale of the Silent", + "IR-DYY": "Vale of the Silent", + "C-DHON": "Vale of the Silent", + "F-D49D": "Vale of the Silent", + "MQ-O27": "Vale of the Silent", + "H-EY0P": "Vale of the Silent", + "UNAG-6": "Vale of the Silent", + "E-SCTX": "Vale of the Silent", + "S6QX-N": "Vale of the Silent", + "IT-YAU": "Vale of the Silent", + "1VK-6B": "Vale of the Silent", + "7-PO3P": "Vale of the Silent", + "1W-0KS": "Vale of the Silent", + "669-IX": "Vale of the Silent", + "0R-F2F": "Vale of the Silent", + "R-P7KL": "Vale of the Silent", + "2DWM-2": "Vale of the Silent", + "XF-PWO": "Vale of the Silent", + "1N-FJ8": "Vale of the Silent", + "VI2K-J": "Vale of the Silent", + "ZLZ-1Z": "Vale of the Silent", + "6Y-WRK": "Vale of the Silent", + "RVCZ-C": "Vale of the Silent", + "5T-KM3": "Vale of the Silent", + "LS9B-9": "Vale of the Silent", + "1-GBBP": "Vale of the Silent", + "C-FP70": "Vale of the Silent", + "T-ZWA1": "Vale of the Silent", + "ZA0L-U": "Vale of the Silent", + "G96R-F": "Vale of the Silent", + "Y-ZXIO": "Vale of the Silent", + "B-E3KQ": "Vale of the Silent", + "Y5J-EU": "Vale of the Silent", + "O-LR1H": "Vale of the Silent", + "G5ED-Y": "Vale of the Silent", + "BR-6XP": "Vale of the Silent", + "8-TFDX": "Vale of the Silent", + "UL-4ZW": "Vale of the Silent", + "A-QRQT": "Vale of the Silent", + "WMBZ-U": "Vale of the Silent", + "PX5-LR": "Vale of the Silent", + "A3-RQ3": "Vale of the Silent", + "9-GBPD": "Vale of the Silent", + "LS-JEP": "Vale of the Silent", + "R-RSZZ": "Vale of the Silent", + "MGAM-4": "Vale of the Silent", + "VORM-W": "Vale of the Silent", + "7G-H7D": "Vale of the Silent", + "Q3-BAY": "Vale of the Silent", + "JZV-F4": "Vale of the Silent", + "WF-1LM": "UUA-F4", + "D95-FQ": "UUA-F4", + "ZSPJ-K": "UUA-F4", + "U1F-86": "UUA-F4", + "T-P7A6": "UUA-F4", + "Y-T3JJ": "UUA-F4", + "F3R-IA": "UUA-F4", + "74-YTJ": "UUA-F4", + "8-RS3U": "UUA-F4", + "OVFN-N": "UUA-F4", + "1Q-BBM": "UUA-F4", + "WXNC-N": "UUA-F4", + "G-EA07": "UUA-F4", + "X-L6BO": "UUA-F4", + "D-PHUA": "UUA-F4", + "3-HXHQ": "UUA-F4", + "18A-NB": "UUA-F4", + "3-J5OQ": "UUA-F4", + "GYF-GD": "UUA-F4", + "W-6TS9": "UUA-F4", + "VIG-VR": "UUA-F4", + "KX-P5C": "UUA-F4", + "N-FJBK": "UUA-F4", + "2-4ZT5": "UUA-F4", + "NVN-6F": "UUA-F4", + "09-8TH": "UUA-F4", + "TI0-AX": "UUA-F4", + "7O-POM": "UUA-F4", + "L6Q-SX": "UUA-F4", + "BFJ-TB": "UUA-F4", + "ZZ7-L6": "UUA-F4", + "L-CHVW": "UUA-F4", + "X0LN-U": "UUA-F4", + "RQAE-M": "UUA-F4", + "7CO-SA": "UUA-F4", + "4G-E5A": "UUA-F4", + "A-VWK9": "UUA-F4", + "JQHP-4": "UUA-F4", + "6Q5K-5": "UUA-F4", + "P-MVFP": "UUA-F4", + "J-Z1UW": "UUA-F4", + "W477-P": "UUA-F4", + "NQ1-BL": "UUA-F4", + "K7A-G8": "UUA-F4", + "HP-PMX": "UUA-F4", + "6BN-K9": "UUA-F4", + "WLE-PY": "UUA-F4", + "EH-HXW": "UUA-F4", + "OS-RR3": "UUA-F4", + "V4-GZL": "UUA-F4", + "4C-Z91": "UUA-F4", + "RU-97T": "UUA-F4", + "1S-1V7": "UUA-F4", + "PE1-R1": "UUA-F4", + "Polaris": "UUA-F4", + "JB-007": "UUA-F4", + "USJ2-M": "UUA-F4", + "7M-RAL": "UUA-F4", + "LPBU-U": "UUA-F4", + "RF-342": "UUA-F4", + "J2V-XY": "UUA-F4", + "Z-JBTR": "UUA-F4", + "S-QNXH": "UUA-F4", + "S94-X8": "UUA-F4", + "J-YQEC": "UUA-F4", + "8MX-OR": "UUA-F4", + "97YC-C": "UUA-F4", + "V-AMD5": "UUA-F4", + "U-JC8X": "UUA-F4", + "1HH3-E": "UUA-F4", + "DUIU-Q": "UUA-F4", + "LQH0-H": "UUA-F4", + "FRW3-2": "UUA-F4", + "9MX-1C": "UUA-F4", + "IED-4U": "UUA-F4", + "N-9EOQ": "UUA-F4", + "6F3-TK": "UUA-F4", + "2E0P-2": "UUA-F4", + "U-ITH5": "UUA-F4", + "N-4G5L": "UUA-F4", + "RB-2EA": "UUA-F4", + "ZK5-42": "UUA-F4", + "YRZ-E4": "UUA-F4", + "A3-PAT": "UUA-F4", + "H55-2R": "UUA-F4", + "P6-DBM": "UUA-F4", + "9XI-0X": "UUA-F4", + "Q8T-MC": "UUA-F4", + "Z-YOJ9": "UUA-F4", + "4T4B-L": "UUA-F4", + "F-JB3H": "UUA-F4", + "XBO7-F": "UUA-F4", + "FI-449": "UUA-F4", + "UA7-U4": "UUA-F4", + "VM-QFU": "UUA-F4", + "PU-1Z8": "UUA-F4", + "IEZW-V": "UUA-F4", + "B-DXO9": "UUA-F4", + "1TS-WN": "UUA-F4", + "16-31U": "UUA-F4", + "H472-N": "UUA-F4", + "U8MM-3": "UUA-F4", + "3C-26I": "UUA-F4", + "9K-VDI": "UUA-F4", + "L-SDU7": "UUA-F4", + "4-IPWK": "UUA-F4", + "Q-KCK3": "UUA-F4", + "WU-FHQ": "Detorid", + "V-4DBR": "Detorid", + "B-5UFY": "Detorid", + "SK42-F": "Detorid", + "EU9-J3": "Detorid", + "PQRE-W": "Detorid", + "OEG-K9": "Detorid", + "0-W778": "Detorid", + "DG-8VJ": "Detorid", + "5J4K-9": "Detorid", + "MD-0AW": "Detorid", + "H-FGJO": "Detorid", + "1KAW-T": "Detorid", + "C5-SUU": "Detorid", + "XSUD-1": "Detorid", + "3-LJW3": "Detorid", + "ZLO3-V": "Detorid", + "P7MI-T": "Detorid", + "JFV-ID": "Detorid", + "3-3EZB": "Detorid", + "52CW-6": "Detorid", + "9-OUGJ": "Detorid", + "4NDT-W": "Detorid", + "GR-X26": "Detorid", + "6OU9-U": "Detorid", + "9N-0HF": "Detorid", + "U-OVFR": "Detorid", + "G3D-ZT": "Detorid", + "D-0UI0": "Detorid", + "L8-WNE": "Detorid", + "1-GBVE": "Detorid", + "GC-LTF": "Detorid", + "NB-ALM": "Detorid", + "LT-XI4": "Detorid", + "L-QQ6P": "Detorid", + "5OJ-G2": "Detorid", + "9-02G0": "Detorid", + "XA5-TY": "Detorid", + "M-XUZZ": "Detorid", + "OFVH-Y": "Detorid", + "2-X0PF": "Detorid", + "1-PGSG": "Detorid", + "QLPX-J": "Detorid", + "A-C5TC": "Detorid", + "RZ-PIY": "Detorid", + "FR46-E": "Detorid", + "SLVP-D": "Detorid", + "0-G8NO": "Detorid", + "QRFJ-Q": "Detorid", + "HZFJ-M": "Detorid", + "77S8-E": "Detorid", + "FMH-OV": "Detorid", + "TYB-69": "Detorid", + "EDQG-L": "Detorid", + "7-P1JO": "Detorid", + "T-0JWP": "Detorid", + "J-L9MA": "Detorid", + "DX-TAR": "Detorid", + "A-7XFN": "Detorid", + "O3-4MN": "Detorid", + "U-MFTL": "Detorid", + "8FN-GP": "Detorid", + "FIDY-8": "Detorid", + "X40H-9": "Detorid", + "F2W-C6": "Detorid", + "KZ9T-C": "Detorid", + "XW2H-V": "Detorid", + "F9O-U9": "Detorid", + "S-51XG": "Detorid", + "E-1XVP": "Detorid", + "E-ACV6": "Detorid", + "BOZ1-O": "Detorid", + "QIMO-2": "Detorid", + "Z-2Y2Y": "Detorid", + "Q0J-RH": "Detorid", + "SAI-T9": "Detorid", + "IAS-I5": "Detorid", + "K7S-FF": "Detorid", + "RT-9WL": "Detorid", + "O5Q7-U": "Detorid", + "62O-UE": "Detorid", + "U0W-DR": "Detorid", + "SY-UWN": "Detorid", + "DX-DFJ": "Detorid", + "X-31TE": "Detorid", + "DVWV-3": "Detorid", + "KE-0FB": "Detorid", + "I-9GI1": "Detorid", + "W6P-7U": "Detorid", + "0IF-26": "Detorid", + "H-93YV": "Detorid", + "E51-JE": "Detorid", + "7-A6XV": "Detorid", + "QXE-1N": "Detorid", + "U69-YC": "Detorid", + "L-L7PE": "Detorid", + "MKIG-5": "Wicked Creek", + "YHEN-G": "Wicked Creek", + "E-JCUS": "Wicked Creek", + "W-QN5X": "Wicked Creek", + "LP1M-Q": "Wicked Creek", + "30-YOU": "Wicked Creek", + "384-IN": "Wicked Creek", + "4F89-U": "Wicked Creek", + "G063-U": "Wicked Creek", + "J7-BDX": "Wicked Creek", + "MLQ-O9": "Wicked Creek", + "L-FM3P": "Wicked Creek", + "X-ARMF": "Wicked Creek", + "8-OZU1": "Wicked Creek", + "0TYR-T": "Wicked Creek", + "GM-50Y": "Wicked Creek", + "G9L-LP": "Wicked Creek", + "MWA-5Q": "Wicked Creek", + "H-HHTH": "Wicked Creek", + "JQU-KY": "Wicked Creek", + "UY5A-D": "Wicked Creek", + "C-62I5": "Wicked Creek", + "ZH-GKG": "Wicked Creek", + "GPLB-C": "Wicked Creek", + "GGE-5Q": "Wicked Creek", + "5E-CMA": "Wicked Creek", + "U104-3": "Wicked Creek", + "M3-KAQ": "Wicked Creek", + "6-L4YC": "Wicked Creek", + "UM-SCG": "Wicked Creek", + "F-3FOY": "Wicked Creek", + "OAIG-0": "Wicked Creek", + "UZ-QXW": "Wicked Creek", + "5DE-QS": "Wicked Creek", + "R0-DMM": "Wicked Creek", + "5Q65-4": "Wicked Creek", + "SR-4EK": "Wicked Creek", + "0RI-OV": "Wicked Creek", + "C-LTXS": "Wicked Creek", + "C0O6-K": "Wicked Creek", + "HD-AJ7": "Wicked Creek", + "G9NE-B": "Wicked Creek", + "SJJ-4F": "Wicked Creek", + "F-QQ5N": "Wicked Creek", + "1-7B6D": "Wicked Creek", + "H6-EYX": "Wicked Creek", + "U-HVIX": "Wicked Creek", + "4-EFLU": "Wicked Creek", + "EIH-IU": "Wicked Creek", + "F-EM4Q": "Wicked Creek", + "1L-OEK": "Wicked Creek", + "MN-Q26": "Wicked Creek", + "5H-SM2": "Wicked Creek", + "4-OS2A": "Wicked Creek", + "YI-GV6": "Wicked Creek", + "SO-X5L": "Wicked Creek", + "XQS-GZ": "Wicked Creek", + "Q-GQHN": "Wicked Creek", + "A-4JOO": "Wicked Creek", + "TP7-KE": "Wicked Creek", + "R4N-LD": "Wicked Creek", + "3Q-VZA": "Wicked Creek", + "M-MBRT": "Wicked Creek", + "HPBE-D": "Wicked Creek", + "GRHS-B": "Wicked Creek", + "J-RXYN": "Wicked Creek", + "DUO-51": "Wicked Creek", + "07-SLO": "Wicked Creek", + "Z-A8FS": "Wicked Creek", + "GPD5-0": "Wicked Creek", + "LKZ-CY": "Wicked Creek", + "F5M-CC": "Wicked Creek", + "TZE-UB": "Wicked Creek", + "WRL4-2": "Wicked Creek", + "V7G-RL": "Wicked Creek", + "XEN7-0": "Wicked Creek", + "L-Z9KJ": "Wicked Creek", + "7K-NSE": "Wicked Creek", + "OR-7N5": "Wicked Creek", + "JEQG-7": "Wicked Creek", + "5NQI-E": "Wicked Creek", + "B-WQDP": "Wicked Creek", + "2-2EWC": "Cache", + "E1W-TB": "Cache", + "D-6H64": "Cache", + "8-BIE3": "Cache", + "LMM7-L": "Cache", + "995-3G": "Cache", + "W2T-TR": "Cache", + "Q-UEN6": "Cache", + "BLMX-B": "Cache", + "M-CNUD": "Cache", + "YE1-9S": "Cache", + "IVP-KA": "Cache", + "04EI-U": "Cache", + "B-T6BT": "Cache", + "VK-A5G": "Cache", + "I6-SYN": "Cache", + "O-5TN1": "Cache", + "8-SPNN": "Cache", + "U-QMOA": "Cache", + "4S0-NP": "Cache", + "K-RMI5": "Cache", + "C-6YHJ": "Cache", + "M53-1V": "Cache", + "E5T-CS": "Cache", + "W4C8-Q": "Cache", + "I-2705": "Cache", + "5F-MG1": "Cache", + "P7-45V": "Cache", + "M-MCP8": "Cache", + "JZ-B5Y": "Cache", + "TPG-DD": "Cache", + "NIF-JE": "Cache", + "BTLH-I": "Cache", + "U93O-A": "Cache", + "0LY-W1": "Cache", + "4YO-QK": "Cache", + "LJ-RJK": "Cache", + "8-VC6H": "Cache", + "LQ-01M": "Cache", + "NG-M8K": "Cache", + "RV5-TT": "Cache", + "8OYE-Z": "Cache", + "K85Y-6": "Cache", + "PKN-NJ": "Cache", + "EIN-QG": "Scalding Pass", + "ARG-3R": "Scalding Pass", + "S-E6ES": "Scalding Pass", + "R-3FBU": "Scalding Pass", + "K7-LDX": "Scalding Pass", + "U-IVGH": "Scalding Pass", + "P-N5N9": "Scalding Pass", + "JMH-PT": "Scalding Pass", + "DE-A7P": "Scalding Pass", + "X9V-15": "Scalding Pass", + "K212-A": "Scalding Pass", + "F-5FDA": "Scalding Pass", + "S1-XTL": "Scalding Pass", + "9PX2-F": "Scalding Pass", + "N3-JBX": "Scalding Pass", + "SG-75T": "Scalding Pass", + "GN-PDU": "Scalding Pass", + "AZ3F-N": "Scalding Pass", + "RNM-Y6": "Scalding Pass", + "V-KDY2": "Scalding Pass", + "FYD-TO": "Scalding Pass", + "ER2O-Y": "Scalding Pass", + "J2-PZ6": "Scalding Pass", + "XV-MWG": "Scalding Pass", + "OAQY-M": "Scalding Pass", + "1V-LI2": "Scalding Pass", + "M9-MLR": "Scalding Pass", + "Q-K2T7": "Scalding Pass", + "LBC-AW": "Scalding Pass", + "2-KPW6": "Scalding Pass", + "H5N-V7": "Scalding Pass", + "HQ-Q1Q": "Scalding Pass", + "WHI-61": "Scalding Pass", + "ZFJH-T": "Scalding Pass", + "I-1B7X": "Scalding Pass", + "G15Z-W": "Scalding Pass", + "AH8-Q7": "Scalding Pass", + "SD4A-2": "Scalding Pass", + "U6K-RG": "Scalding Pass", + "V-S9YY": "Scalding Pass", + "F2-NXA": "Scalding Pass", + "NSBE-L": "Scalding Pass", + "8Q-T7B": "Scalding Pass", + "WV0D-1": "Scalding Pass", + "ZNF-OK": "Scalding Pass", + "C8-7AS": "Scalding Pass", + "4E-EZS": "Scalding Pass", + "A-80UA": "Scalding Pass", + "U2-28D": "Scalding Pass", + "LQ-OAI": "Scalding Pass", + "5-MQQ7": "Scalding Pass", + "6-EQYE": "Scalding Pass", + "03-OR2": "Scalding Pass", + "JLO-Z3": "Scalding Pass", + "IAK-JW": "Scalding Pass", + "KZFV-4": "Scalding Pass", + "WO-GC0": "Scalding Pass", + "RYC-19": "Scalding Pass", + "X2-ZA5": "Scalding Pass", + "28Y9-P": "Scalding Pass", + "Q4C-S5": "Scalding Pass", + "B-1UJC": "Scalding Pass", + "Q-NA5H": "Scalding Pass", + "4-CM8I": "Scalding Pass", + "ZDB-HT": "Scalding Pass", + "1QZ-Y9": "Scalding Pass", + "HJ-BCH": "Scalding Pass", + "QPTT-F": "Scalding Pass", + "9M-M0P": "Scalding Pass", + "9BC-EB": "Scalding Pass", + "WFFE-4": "Scalding Pass", + "71-UTX": "Scalding Pass", + "PU-UMM": "Scalding Pass", + "6-KPAB": "Scalding Pass", + "Y5-E1U": "Scalding Pass", + "4-43BW": "Scalding Pass", + "8CN-CH": "Scalding Pass", + "V-F6DQ": "Scalding Pass", + "3S-6VU": "Scalding Pass", + "1-7HVI": "Scalding Pass", + "OX-S7P": "Scalding Pass", + "KDG-TA": "Insmother", + "KD-KPR": "Insmother", + "PT-21C": "Insmother", + "Z182-R": "Insmother", + "EKPB-3": "Insmother", + "5M2-KP": "Insmother", + "TK-DLH": "Insmother", + "C8H5-X": "Insmother", + "O-7LAI": "Insmother", + "7L3-JS": "Insmother", + "WF4C-8": "Insmother", + "TZN-2V": "Insmother", + "8EF-58": "Insmother", + "4DS-OI": "Insmother", + "XQP-9C": "Insmother", + "W-6GBI": "Insmother", + "XKH-6O": "Insmother", + "S0U-MO": "Insmother", + "F39H-1": "Insmother", + "V-QXXK": "Insmother", + "2-Q4YG": "Insmother", + "2JT-3Q": "Insmother", + "I3CR-F": "Insmother", + "7-JT09": "Insmother", + "AGCP-I": "Insmother", + "M4-GJ6": "Insmother", + "5-2PQU": "Insmother", + "SN9-3Z": "Insmother", + "6BJH-3": "Insmother", + "U-UTU9": "Insmother", + "1TG7-W": "Insmother", + "QYD-WK": "Insmother", + "R959-U": "Insmother", + "A-TJ0G": "Insmother", + "88A-RA": "Insmother", + "8G-2FP": "Insmother", + "C-J6MT": "Insmother", + "78-0R6": "Insmother", + "MSG-BZ": "Insmother", + "8-WYQZ": "Insmother", + "4M-QXK": "Insmother", + "X5-0EM": "Insmother", + "G-EURJ": "Insmother", + "SHBF-V": "Insmother", + "RERZ-L": "Insmother", + "0UBC-R": "Insmother", + "3U-48K": "Insmother", + "EFM-C4": "Insmother", + "YPW-M4": "Insmother", + "Q7-FZ8": "Insmother", + "L5-UWT": "Insmother", + "74-VZA": "Insmother", + "I-1QKL": "Insmother", + "GK5Z-T": "Insmother", + "RQN-OO": "Insmother", + "67Y-NR": "Insmother", + "GDHN-K": "Insmother", + "QTME-D": "Insmother", + "A24L-V": "Insmother", + "4CJ-AC": "Insmother", + "EUU-4N": "Insmother", + "Q-3HS5": "Insmother", + "3AE-CP": "Insmother", + "0-VG7A": "Insmother", + "9OLQ-6": "Insmother", + "MOCW-2": "Insmother", + "ZO-4AR": "Insmother", + "MJ-LGH": "Insmother", + "F2A-GX": "Insmother", + "RD-FWY": "Insmother", + "VBPT-T": "Insmother", + "KS-1TS": "Insmother", + "X0-6LH": "Insmother", + "FN0-QS": "Insmother", + "F3-8X2": "Insmother", + "N7-BIY": "Insmother", + "TTP-2B": "Insmother", + "LVL-GZ": "Insmother", + "EJ48-O": "Insmother", + "ROJ-B0": "Insmother", + "DFH-V5": "Insmother", + "B-II34": "Insmother", + "4LB-EL": "Insmother", + "UDE-FX": "Insmother", + "5IH-GL": "Insmother", + "C1G-XC": "Insmother", + "04-EHC": "Insmother", + "3-0FYP": "Insmother", + "N-O53U": "Insmother", + "HZ-O18": "Insmother", + "D-P1EH": "Insmother", + "74L2-U": "Insmother", + "HL-VZX": "Insmother", + "38NZ-1": "Insmother", + "W-MF6J": "Insmother", + "O-9G5Y": "Insmother", + "27-HP0": "Insmother", + "X1-IZ0": "Insmother", + "RZ-TI6": "Insmother", + "FX4L-2": "Insmother", + "1ZF-PJ": "Insmother", + "HFC-AQ": "Insmother", + "0-6VZ5": "Insmother", + "GB-6X5": "Insmother", + "7EX-14": "Insmother", + "N7-KGJ": "Insmother", + "VD-8QY": "Insmother", + "J-ZYSZ": "Insmother", + "5C-RPA": "Insmother", + "CR2-PQ": "Insmother", + "E-OGL4": "Tribute", + "J-GAMP": "Tribute", + "M-OEE8": "Tribute", + "V0DF-2": "Tribute", + "FY0W-N": "Tribute", + "MJI3-8": "Tribute", + "A-DDGY": "Tribute", + "F-RT6Q": "Tribute", + "B-S42H": "Tribute", + "NL6V-7": "Tribute", + "F-749O": "Tribute", + "0-YMBJ": "Tribute", + "UMI-KK": "Tribute", + "GKP-YT": "Tribute", + "AW1-2I": "Tribute", + "15W-GC": "Tribute", + "N-FK87": "Tribute", + "C2X-M5": "Tribute", + "MSHD-4": "Tribute", + "H-W9TY": "Tribute", + "PNDN-V": "Tribute", + "D7-ZAC": "Tribute", + "SH1-6P": "Tribute", + "TRKN-L": "Tribute", + "O-0ERG": "Tribute", + "WH-JCA": "Tribute", + "Q-CAB2": "Tribute", + "PBD-0G": "Tribute", + "L-1HKR": "Tribute", + "9GI-FB": "Tribute", + "3G-LHB": "Tribute", + "DBT-GB": "Tribute", + "U-W3WS": "Tribute", + "DL1C-E": "Tribute", + "YLS8-J": "Tribute", + "2ISU-Y": "Tribute", + "X-CFN6": "Tribute", + "9SL-K9": "Tribute", + "Y-PZHM": "Tribute", + "OY-UZ1": "Tribute", + "S8-NSQ": "Tribute", + "GIH-ZG": "Tribute", + "V7-FB4": "Tribute", + "XD-TOV": "Tribute", + "K-6SNI": "Tribute", + "L-VXTK": "Tribute", + "C8VC-S": "Tribute", + "W-UQA5": "Tribute", + "W6VP-Y": "Tribute", + "IMK-K1": "Tribute", + "NJ4X-S": "Tribute", + "F-G7BO": "Tribute", + "2CG-5V": "Tribute", + "QFF-O6": "Tribute", + "NIH-02": "Great Wildlands", + "JPL-RA": "Great Wildlands", + "NK-7XO": "Great Wildlands", + "E02-IK": "Great Wildlands", + "N-DQ0D": "Great Wildlands", + "M-MD3B": "Great Wildlands", + "FVXK-D": "Great Wildlands", + "6EG7-R": "Great Wildlands", + "56D-TC": "Great Wildlands", + "2X7Z-L": "Great Wildlands", + "8DL-CP": "Great Wildlands", + "UMDQ-6": "Great Wildlands", + "504Z-V": "Great Wildlands", + "F8K-WQ": "Great Wildlands", + "AB-FZE": "Great Wildlands", + "N-6Z8B": "Great Wildlands", + "YUY-LM": "Great Wildlands", + "NE-3GR": "Great Wildlands", + "Y4-GQV": "Great Wildlands", + "7-IDWY": "Great Wildlands", + "AZF-GH": "Great Wildlands", + "UT-UZB": "Great Wildlands", + "M-EKDF": "Great Wildlands", + "CRXA-Y": "Great Wildlands", + "VXO-OM": "Great Wildlands", + "BY5-V8": "Great Wildlands", + "TET3-B": "Great Wildlands", + "VKU-BG": "Great Wildlands", + "WPR-EI": "Great Wildlands", + "0NV-YU": "Great Wildlands", + "V-2GYS": "Great Wildlands", + "168-6H": "Great Wildlands", + "W-RFUO": "Great Wildlands", + "AI-EVH": "Great Wildlands", + "F-MKH3": "Great Wildlands", + "ZM-DNR": "Great Wildlands", + "GF-3FL": "Great Wildlands", + "ZJ-GOU": "Great Wildlands", + "QQ3-YI": "Great Wildlands", + "9-34L5": "Great Wildlands", + "0R-GZQ": "Great Wildlands", + "QM-20X": "Great Wildlands", + "8YC-AN": "Great Wildlands", + "7Q-8Z2": "Great Wildlands", + "SUR-F7": "Great Wildlands", + "OK-6XN": "Great Wildlands", + "Q2FL-T": "Great Wildlands", + "Y7-XFD": "Great Wildlands", + "U3K-4A": "Great Wildlands", + "P1T-LP": "Great Wildlands", + "R-ESG0": "Great Wildlands", + "CI4M-T": "Great Wildlands", + "I-QRJA": "Great Wildlands", + "M-YWAL": "Great Wildlands", + "DE71-9": "Great Wildlands", + "7JF-0Z": "Great Wildlands", + "IX8-JB": "Great Wildlands", + "WTIE-6": "Great Wildlands", + "Y-DSSK": "Great Wildlands", + "F5-CGW": "Great Wildlands", + "H9S-WC": "Great Wildlands", + "B-ROFP": "Great Wildlands", + "1L-AED": "Great Wildlands", + "1C-953": "Great Wildlands", + "SL-YBS": "Great Wildlands", + "UNJ-GX": "Great Wildlands", + "0PI4-E": "Great Wildlands", + "6WT-BE": "Great Wildlands", + "L1S-G1": "Great Wildlands", + "9SNK-O": "Great Wildlands", + "B-VIP9": "Great Wildlands", + "LXTC-S": "Great Wildlands", + "WE3-BX": "Great Wildlands", + "H7O-JZ": "Great Wildlands", + "H-8F5Q": "Great Wildlands", + "O-RXCZ": "Great Wildlands", + "4M-P1I": "Great Wildlands", + "P7UZ-T": "Great Wildlands", + "PUZ-IO": "Great Wildlands", + "HB-1NJ": "Great Wildlands", + "EOE3-N": "Great Wildlands", + "F7A-MR": "Great Wildlands", + "O-8SOC": "Great Wildlands", + "OJOS-T": "Great Wildlands", + "V89M-R": "Great Wildlands", + "66U-1P": "Great Wildlands", + "BRT-OP": "Great Wildlands", + "JUK0-1": "Great Wildlands", + "V-IH6B": "Great Wildlands", + "52V6-B": "Great Wildlands", + "PUC-JZ": "Great Wildlands", + "SB-23C": "Great Wildlands", + "5FCV-A": "Great Wildlands", + "O-OVOQ": "Great Wildlands", + "92-B0X": "Great Wildlands", + "0-3VW8": "Great Wildlands", + "28-QWU": "Great Wildlands", + "UD-AOK": "Great Wildlands", + "M9U-75": "Great Wildlands", + "N-RAEL": "Great Wildlands", + "K-IYNW": "Great Wildlands", + "H-ADOC": "Curse", + "G-G78S": "Curse", + "UW9B-F": "Curse", + "ZZ-ZWC": "Curse", + "OSY-UD": "Curse", + "K-MGJ7": "Curse", + "JWJ-P1": "Curse", + "V-IUEL": "Curse", + "0SHT-A": "Curse", + "D87E-A": "Curse", + "K-B2D3": "Curse", + "PO4F-3": "Curse", + "J7A-UR": "Curse", + "5E-VR8": "Curse", + "V7D-JD": "Curse", + "HLW-HP": "Curse", + "8G-MQV": "Curse", + "RA-NXN": "Curse", + "VOL-MI": "Curse", + "KLMT-W": "Curse", + "XX9-WV": "Curse", + "AAM-1A": "Curse", + "EW-JR5": "Curse", + "YKE4-3": "Curse", + "CL-85V": "Curse", + "K-QWHE": "Curse", + "MDD-79": "Curse", + "RMOC-W": "Curse", + "ES-UWY": "Curse", + "S1DP-Y": "Curse", + "Y-DW5K": "Curse", + "M-N7WD": "Curse", + "QFEW-K": "Curse", + "CVY-UC": "Curse", + "EQX-AE": "Curse", + "G-R4W1": "Curse", + "BPK-XK": "Curse", + "LJ-YSW": "Curse", + "Y-K50G": "Curse", + "K88X-J": "Curse", + "G-0Q86": "Curse", + "CL-1JE": "Curse", + "J4UD-J": "Curse", + "Hemin": "Curse", + "Utopia": "Curse", + "Jorund": "Curse", + "Doril": "Curse", + "Litom": "Curse", + "Farit": "Curse", + "Jamunda": "Curse", + "TD-4XL": "Malpais", + "IBOX-2": "Malpais", + "8AB-Q4": "Malpais", + "VW-PXL": "Malpais", + "JA-G0T": "Malpais", + "IF-KD1": "Malpais", + "7-YHRX": "Malpais", + "Y6-9LF": "Malpais", + "X-PQEX": "Malpais", + "N-H95C": "Malpais", + "NSI-MW": "Malpais", + "N-YLOE": "Malpais", + "NBO-O0": "Malpais", + "F-TQWO": "Malpais", + "0-TRV1": "Malpais", + "13-49W": "Malpais", + "6UT-1K": "Malpais", + "O8W-5O": "Malpais", + "LH-PLU": "Malpais", + "AZA-QE": "Malpais", + "8-2JZA": "Malpais", + "ZT-L3S": "Malpais", + "VVB-QH": "Malpais", + "Z-DDVJ": "Malpais", + "7-2Z93": "Malpais", + "B-VFDD": "Malpais", + "A0M-R8": "Malpais", + "LY-WRW": "Malpais", + "9F-ERQ": "Malpais", + "QCGG-Q": "Malpais", + "1NZV-7": "Malpais", + "NIM-FY": "Malpais", + "DAI-SH": "Malpais", + "V3P-AZ": "Malpais", + "C-KW6X": "Malpais", + "X1W-AL": "Malpais", + "F-WZYG": "Malpais", + "S-R9J2": "Malpais", + "XU-BF8": "Malpais", + "RIU-GC": "Malpais", + "Z0H2-4": "Malpais", + "63-7Q6": "Malpais", + "XCZ5-Y": "Malpais", + "NRD-5Q": "Malpais", + "W5-205": "Malpais", + "T-4H0B": "Malpais", + "Z-EKCY": "Malpais", + "SH-YZY": "Malpais", + "O7-RFZ": "Malpais", + "CLW-SI": "Malpais", + "5-A0PX": "Malpais", + "R-RMDH": "Malpais", + "2XI8-Y": "Malpais", + "5B-YDD": "Malpais", + "W-XY4J": "Malpais", + "PWPY-4": "Malpais", + "QZ1-OH": "Malpais", + "Y-XZA7": "Malpais", + "1-EVAX": "Malpais", + "I8-AJY": "Malpais", + "6-WMKE": "Malpais", + "J-Z8C2": "Malpais", + "XTVZ-E": "Malpais", + "APES-G": "Malpais", + "B2J-5N": "Malpais", + "2Z-HPQ": "Malpais", + "NBW-GD": "Malpais", + "YM-SRU": "Malpais", + "LO5-LN": "Malpais", + "06-70G": "Malpais", + "UYG-YX": "Malpais", + "GL6S-2": "Malpais", + "RUF3-O": "Malpais", + "C-NMG9": "Malpais", + "P3X-TN": "Malpais", + "N6NK-J": "Malpais", + "TP-APY": "Malpais", + "9NI-FW": "Malpais", + "H-EBQG": "Malpais", + "DOA-YU": "Malpais", + "ZOPZ-6": "Malpais", + "863P-X": "Malpais", + "ZO-YJZ": "Malpais", + "6A-FUY": "Malpais", + "HG-YEQ": "Malpais", + "2FL-5W": "Malpais", + "QSCO-D": "Malpais", + "RXTY-4": "Malpais", + "RSE-PT": "Malpais", + "WVJU-4": "Malpais", + "7T-0QS": "Malpais", + "RWML-A": "Malpais", + "V-JCJS": "Malpais", + "8C-VE3": "Malpais", + "S5W-1Z": "Malpais", + "IL-OL1": "Malpais", + "POQP-K": "Malpais", + "FO9-FZ": "Malpais", + "4QY-NT": "Malpais", + "0-N1BJ": "Malpais", + "T-8GWA": "Malpais", + "UW-6MW": "Malpais", + "F9E-KX": "Catch", + "9KOE-A": "Catch", + "U-QVWD": "Catch", + "B-3QPD": "Catch", + "36N-HZ": "Catch", + "SV5-8N": "Catch", + "HY-RWO": "Catch", + "WD-VTV": "Catch", + "HED-GP": "Catch", + "V-3YG7": "Catch", + "QSM-LM": "Catch", + "KDF-GY": "Catch", + "QBQ-RF": "Catch", + "9-8GBA": "Catch", + "6-K738": "Catch", + "ZXIC-7": "Catch", + "2J-WJY": "Catch", + "1P-WGB": "Catch", + "F4R2-Q": "Catch", + "K0CN-3": "Catch", + "WLAR-J": "Catch", + "L7XS-5": "Catch", + "VA6-DR": "Catch", + "S-U2VD": "Catch", + "GE-94X": "Catch", + "GMLH-K": "Catch", + "W9-DID": "Catch", + "KW-I6T": "Catch", + "EX-0LQ": "Catch", + "MB-NKE": "Catch", + "G-7WUF": "Catch", + "6-MM99": "Catch", + "JBY6-F": "Catch", + "FZ-6A5": "Catch", + "RNF-YH": "Catch", + "I-8D0G": "Catch", + "R-K4QY": "Catch", + "JWZ2-V": "Catch", + "OGL8-Q": "Catch", + "GJ0-OJ": "Catch", + "A-803L": "Catch", + "WQH-4K": "Catch", + "J-ODE7": "Catch", + "Q-S7ZD": "Catch", + "6X7-JO": "Catch", + "GE-8JV": "Catch", + "3-OKDA": "Catch", + "3GD6-8": "Catch", + "4M-HGL": "Catch", + "MY-W1V": "Catch", + "AX-DOT": "Catch", + "YHN-3K": "Catch", + "CB4-Q2": "Catch", + "CBL-XP": "Catch", + "WJ-9YO": "Catch", + "UQ-PWD": "Catch", + "N-8BZ6": "Catch", + "A-VILQ": "Catch", + "X3FQ-W": "Catch", + "3-SFWG": "Catch", + "MUXX-4": "Catch", + "E1-4YH": "Catch", + "B-XJX4": "Catch", + "AOK-WQ": "Catch", + "E3-SDZ": "Catch", + "7LHB-Z": "Catch", + "8B-2YA": "Catch", + "SNFV-I": "Catch", + "HP-64T": "Catch", + "V2-VC2": "Catch", + "L-B55M": "Catch", + "CX65-5": "Catch", + "JA-O6J": "Catch", + "ZQ-Z3Y": "Catch", + "G-AOTH": "Catch", + "TA3T-3": "Catch", + "E-YJ8G": "Catch", + "J6QB-P": "Catch", + "KA6D-K": "Catch", + "7MD-S1": "Catch", + "ERVK-P": "Catch", + "UL-7I8": "Catch", + "BR-N97": "Catch", + "IS-R7P": "Catch", + "S25C-K": "Catch", + "K717-8": "Catch", + "NH-1X6": "Catch", + "KH0Z-0": "Catch", + "5-N2EY": "Catch", + "KB-U56": "Catch", + "JGW-OT": "Catch", + "UCG4-B": "Catch", + "BUZ-DB": "Catch", + "QETZ-W": "Catch", + "WFC-MY": "Catch", + "Q-U96U": "Catch", + "X4-WL0": "Catch", + "W-MPTH": "Catch", + "4NBN-9": "Catch", + "EX6-AO": "Catch", + "CZK-ZQ": "Catch", + "CNC-4V": "Catch", + "Y-PNRL": "Catch", + "FAT-6P": "Catch", + "6BPS-T": "Catch", + "25S-6P": "Catch", + "RR-D05": "Catch", + "4-07MU": "Catch", + "Y-W1Q3": "Venal", + "Y6-HPG": "Venal", + "Z-GY5S": "Venal", + "KK-L97": "Venal", + "R-KZK7": "Venal", + "9-R6GU": "Venal", + "N-Q5PW": "Venal", + "P-FSQE": "Venal", + "H-PA29": "Venal", + "1-Y6KI": "Venal", + "YP-J33": "Venal", + "D-8SI1": "Venal", + "9-266Q": "Venal", + "K3JR-J": "Venal", + "CSOA-B": "Venal", + "6W-HRH": "Venal", + "N5Y-4N": "Venal", + "MQFX-Q": "Venal", + "9-8BL8": "Venal", + "N6G-H3": "Venal", + "3A1P-N": "Venal", + "OZ-VAE": "Venal", + "A-AFGR": "Venal", + "92K-H2": "Venal", + "AA-YRK": "Venal", + "BV-1JG": "Venal", + "0-BFTQ": "Venal", + "SS-GED": "Venal", + "AJCJ-1": "Venal", + "6NJ8-V": "Venal", + "Y-4CFK": "Venal", + "HBD-CC": "Venal", + "P-GKF5": "Venal", + "E-7U8U": "Venal", + "0-XIDJ": "Venal", + "SBL5-R": "Venal", + "O-TVTD": "Venal", + "8CIX-S": "Venal", + "D-SKWC": "Venal", + "4RX-EE": "Venal", + "V3X-L8": "Venal", + "N0C-UN": "Venal", + "VG-6CH": "Venal", + "Z0-TJW": "Venal", + "QHJ-FW": "Venal", + "9IPC-E": "Venal", + "EIV-1W": "Venal", + "S-1ZXZ": "Venal", + "N-5476": "Venal", + "PZOZ-K": "Venal", + "W3KK-R": "Venal", + "92D-OI": "Venal", + "EK2-ET": "Venal", + "SE-SHZ": "Venal", + "JURU-T": "Venal", + "MC6-5J": "Venal", + "65V-RH": "Venal", + "4-7IL9": "Venal", + "2PLH-3": "Venal", + "RQ9-OZ": "Venal", + "B-CZXG": "Venal", + "0-O2UT": "Venal", + "Q61Y-F": "Venal", + "PF-QHK": "Venal", + "XW-6TC": "Venal", + "Q-7SUI": "Venal", + "VVD-O6": "Venal", + "6ZJ-SC": "Venal", + "P-VYVL": "Venal", + "HD-JVQ": "Venal", + "H-AJ27": "Venal", + "M2-2V1": "Venal", + "2TH-3F": "Venal", + "E1F-E5": "Venal", + "4S-PVC": "Venal", + "WLF-D3": "Venal", + "LHJ-2G": "Venal", + "SHJO-J": "Venal", + "6UQ-4U": "Venal", + "430-BE": "Venal", + "OJ-CT4": "Venal", + "AZ-UWB": "Venal", + "H-S5BM": "Venal", + "FHB-QA": "Venal", + "Z3U-GI": "Venal", + "B3QP-K": "Venal", + "GVZ-1W": "Venal", + "G9D-XW": "Venal", + "42XJ-N": "Venal", + "L-IE41": "Venal", + "VG-QW1": "Venal", + "2IBE-N": "Venal", + "YJ3-UT": "Venal", + "ZD4-G9": "Venal", + "C2-DDA": "Venal", + "Dantumi": "Lonetrek", + "Antiainen": "Lonetrek", + "Ossa": "Lonetrek", + "Semiki": "Lonetrek", + "Kiskoken": "Lonetrek", + "Aurohunen": "Lonetrek", + "Veisto": "Lonetrek", + "Sobaseki": "Lonetrek", + "Funtanainen": "Lonetrek", + "Isikemi": "Lonetrek", + "Uosusuokko": "Lonetrek", + "Hageken": "Lonetrek", + "Uemisaisen": "Lonetrek", + "Sotrentaira": "Lonetrek", + "Ouranienen": "Lonetrek", + "Erenta": "Lonetrek", + "Kino": "Lonetrek", + "Raussinen": "Lonetrek", + "Iidoken": "Lonetrek", + "Tsuguwa": "Lonetrek", + "Nourvukaiken": "Lonetrek", + "Sarekuwa": "Lonetrek", + "Ekura": "Lonetrek", + "Tunttaras": "Lonetrek", + "Vellaine": "Lonetrek", + "Arvasaras": "Lonetrek", + "Akonoinen": "Lonetrek", + "Vaajaita": "Lonetrek", + "Autaris": "Lonetrek", + "Jan": "Lonetrek", + "Saatuban": "Lonetrek", + "Isikano": "Lonetrek", + "Mara": "Lonetrek", + "Isanamo": "Lonetrek", + "Pakkonen": "Lonetrek", + "Piekura": "Lonetrek", + "Amsen": "Lonetrek", + "Malkalen": "Lonetrek", + "Korama": "Lonetrek", + "Ylandoki": "Lonetrek", + "Aakari": "Lonetrek", + "Isseras": "Lonetrek", + "Aunenen": "Lonetrek", + "Elonaya": "Lonetrek", + "Litiura": "Lonetrek", + "Nonni": "Lonetrek", + "Passari": "Lonetrek", + "Piak": "Lonetrek", + "Airkio": "Lonetrek", + "Kakakela": "Lonetrek", + "Kamokor": "Lonetrek", + "Todaki": "Lonetrek", + "Ruvas": "Lonetrek", + "Umokka": "Lonetrek", + "Kirras": "Lonetrek", + "Autama": "Lonetrek", + "Tsukuras": "Lonetrek", + "Nani": "Lonetrek", + "Ajanen": "Lonetrek", + "Kuoka": "Lonetrek", + "Liukikka": "Lonetrek", + "Rauntaka": "Lonetrek", + "Aikantoh": "Lonetrek", + "Atai": "Lonetrek", + "Daras": "Lonetrek", + "Otalieto": "Lonetrek", + "Iitanmadan": "Lonetrek", + "Jotenen": "Lonetrek", + "Haajinen": "Lonetrek", + "Oipo": "Lonetrek", + "Isinokka": "Lonetrek", + "Yoma": "Lonetrek", + "Ibura": "Lonetrek", + "Torrinos": "Lonetrek", + "Endatoh": "Lonetrek", + "Aivoli": "Lonetrek", + "Uesuro": "Lonetrek", + "Oishami": "Lonetrek", + "Elanoda": "Lonetrek", + "Ohbochi": "Lonetrek", + "Isie": "Lonetrek", + "Tamo": "Lonetrek", + "Nannaras": "Lonetrek", + "Anin": "Lonetrek", + "Karjataimon": "Lonetrek", + "Tartoken": "Lonetrek", + "Saranen": "Lonetrek", + "Vuorrassi": "Lonetrek", + "Oimmo": "Lonetrek", + "Nalvula": "Lonetrek", + "Otsasai": "Lonetrek", + "Taisy": "Lonetrek", + "Hakonen": "Lonetrek", + "Jouvulen": "Lonetrek", + "Akiainavas": "Lonetrek", + "Kappas": "Lonetrek", + "Hitanishio": "Lonetrek", + "Ichinumi": "Lonetrek", + "PZP1-D": "J7HZ-F", + "R1KE-A": "J7HZ-F", + "JGDF-B": "J7HZ-F", + "1SR-HT": "J7HZ-F", + "SQ-2XA": "J7HZ-F", + "Z-FYJR": "J7HZ-F", + "ZA6-9N": "J7HZ-F", + "J1-6CJ": "J7HZ-F", + "7H-Z5R": "J7HZ-F", + "0RZ5-2": "J7HZ-F", + "A9-NB6": "J7HZ-F", + "LG1-TA": "J7HZ-F", + "TNK-BQ": "J7HZ-F", + "E2AX-5": "J7HZ-F", + "HPE-KP": "J7HZ-F", + "THS-MN": "J7HZ-F", + "UBES-K": "J7HZ-F", + "I-R8B0": "J7HZ-F", + "QIW-TQ": "J7HZ-F", + "WLL-QX": "J7HZ-F", + "BJC4-8": "J7HZ-F", + "PQA-9K": "J7HZ-F", + "S5-U0R": "J7HZ-F", + "CW-R71": "J7HZ-F", + "QO-3LC": "J7HZ-F", + "3E-ER7": "J7HZ-F", + "REZ-YZ": "J7HZ-F", + "OU-AIT": "J7HZ-F", + "VYX2-I": "J7HZ-F", + "5-P3CQ": "J7HZ-F", + "M-FDTD": "J7HZ-F", + "54-VNO": "J7HZ-F", + "IAMZ-5": "J7HZ-F", + "HD3-JK": "J7HZ-F", + "PBXG-A": "J7HZ-F", + "9-ERCP": "J7HZ-F", + "KN7M-N": "J7HZ-F", + "Z-D1DW": "J7HZ-F", + "FO-3PJ": "J7HZ-F", + "6-QXE6": "J7HZ-F", + "N-FKXV": "J7HZ-F", + "X7-8IG": "J7HZ-F", + "R-G1SF": "J7HZ-F", + "6-NCE7": "J7HZ-F", + "WDJQ-G": "J7HZ-F", + "JS3-RS": "J7HZ-F", + "JX-T1W": "J7HZ-F", + "CZ-CED": "J7HZ-F", + "BKK4-H": "J7HZ-F", + "Y-4V7U": "J7HZ-F", + "L-TPN0": "J7HZ-F", + "3-XORH": "J7HZ-F", + "G1VU-H": "J7HZ-F", + "W6H6-K": "J7HZ-F", + "6-23NU": "J7HZ-F", + "DVAR-P": "J7HZ-F", + "J-JS0D": "J7HZ-F", + "VR3-PS": "J7HZ-F", + "LH-J8H": "J7HZ-F", + "I9D-0D": "J7HZ-F", + "HGB-C6": "J7HZ-F", + "2L5-FI": "J7HZ-F", + "RS08-B": "J7HZ-F", + "4U-14I": "J7HZ-F", + "H-EDXD": "J7HZ-F", + "8-ULAA": "J7HZ-F", + "KF1-DU": "J7HZ-F", + "W-WQM5": "J7HZ-F", + "G5J-LH": "J7HZ-F", + "H7OL-I": "J7HZ-F", + "TO21-U": "J7HZ-F", + "RN-5K9": "J7HZ-F", + "0M-M64": "J7HZ-F", + "W5-SGC": "J7HZ-F", + "8RV-1L": "J7HZ-F", + "1C-TD6": "J7HZ-F", + "YBYX-1": "J7HZ-F", + "L-WG68": "The Spire", + "E4-E8W": "The Spire", + "HIK-MC": "The Spire", + "B9EA-G": "The Spire", + "E-BFLT": "The Spire", + "GZM-KB": "The Spire", + "5LAJ-8": "The Spire", + "C6C-K9": "The Spire", + "AL-JSG": "The Spire", + "ETO-OT": "The Spire", + "KPI-OW": "The Spire", + "A-J6SN": "The Spire", + "OTJ-4W": "The Spire", + "AG-SYG": "The Spire", + "1I5-0V": "The Spire", + "VX1-HV": "The Spire", + "JNG7-K": "The Spire", + "K-XJJT": "The Spire", + "FO1U-K": "The Spire", + "6U-1RX": "The Spire", + "Y4OK-W": "The Spire", + "P-NI4K": "The Spire", + "T6T-BQ": "The Spire", + "N-PS2Y": "The Spire", + "K-BBYU": "The Spire", + "0J-MQW": "The Spire", + "XT-1E0": "The Spire", + "3ET-G8": "The Spire", + "MOSA-I": "The Spire", + "B6-XE8": "The Spire", + "JLH-FN": "The Spire", + "DFTK-D": "The Spire", + "4HF-4R": "The Spire", + "Y8K-5B": "The Spire", + "L7-BLT": "The Spire", + "8P-LKL": "The Spire", + "Q-UVY6": "The Spire", + "RXA-W1": "The Spire", + "QFU-4S": "The Spire", + "QQGH-G": "The Spire", + "VK6-EZ": "The Spire", + "JVA-FE": "The Spire", + "P65-TA": "The Spire", + "G-VFVB": "The Spire", + "Y4B-BQ": "The Spire", + "EU-WFW": "The Spire", + "K-YL9T": "The Spire", + "GTB-O4": "The Spire", + "6W-6O9": "The Spire", + "H4X-0I": "The Spire", + "C-BHDN": "The Spire", + "R-RE2B": "The Spire", + "4DH-ST": "The Spire", + "OSW-0P": "The Spire", + "GF-GR7": "The Spire", + "DVN6-0": "The Spire", + "Z19-B8": "The Spire", + "HPMN-V": "The Spire", + "XR-ZL7": "The Spire", + "U1-VHY": "The Spire", + "OTJ9-E": "The Spire", + "LH-LY1": "The Spire", + "7-QOYS": "The Spire", + "KS8G-M": "The Spire", + "ZWM-BB": "The Spire", + "S-CUEA": "The Spire", + "L-EUY2": "The Spire", + "JL-ZUQ": "The Spire", + "X-KHRZ": "The Spire", + "WIW-X8": "The Spire", + "QRH-BF": "The Spire", + "M-NP5O": "The Spire", + "2-NF2Z": "A821-A", + "0Z-VHC": "A821-A", + "9-BUSQ": "A821-A", + "LQB-TC": "A821-A", + "II-1B3": "A821-A", + "6-HFD6": "A821-A", + "P3UD-M": "A821-A", + "LCN-0V": "A821-A", + "FX-XMW": "A821-A", + "G-N6MC": "A821-A", + "7-8XK0": "A821-A", + "90G-OA": "A821-A", + "DT-7EO": "A821-A", + "B-Y06L": "A821-A", + "HHQ-8L": "A821-A", + "Z-KPAR": "A821-A", + "8U-RZH": "A821-A", + "2RV-06": "A821-A", + "CLDT-L": "A821-A", + "QU7-EE": "A821-A", + "UC-X28": "A821-A", + "R79-I7": "A821-A", + "E-RPGP": "A821-A", + "ZV-KZO": "A821-A", + "NSE-U1": "A821-A", + "KER-EU": "A821-A", + "69A-54": "A821-A", + "M9-OS2": "A821-A", + "5V-YL6": "A821-A", + "8-UWFS": "A821-A", + "PQWA-L": "A821-A", + "BWO-UU": "A821-A", + "SQVI-U": "A821-A", + "T-YWDD": "A821-A", + "DLY-RG": "A821-A", + "T-C5A0": "A821-A", + "UP-L3Y": "A821-A", + "F-KBNV": "A821-A", + "JL-P9P": "A821-A", + "FR-RCH": "A821-A", + "FNS3-F": "A821-A", + "7BA-TK": "A821-A", + "IAWJ-X": "A821-A", + "50-TJY": "A821-A", + "3-CE1R": "A821-A", + "0IRK-R": "A821-A", + "Tividu": "Tash-Murkon", + "Tendhyes": "Tash-Murkon", + "Goram": "Tash-Murkon", + "Anjedin": "Tash-Murkon", + "Adahum": "Tash-Murkon", + "Ahrosseas": "Tash-Murkon", + "Riramia": "Tash-Murkon", + "Nafomeh": "Tash-Murkon", + "Pimsu": "Tash-Murkon", + "Jarzalad": "Tash-Murkon", + "Matyas": "Tash-Murkon", + "Imeshasa": "Tash-Murkon", + "Ivih": "Tash-Murkon", + "Seil": "Tash-Murkon", + "Mani": "Tash-Murkon", + "Sehmosh": "Tash-Murkon", + "Dabrid": "Tash-Murkon", + "Gyerzen": "Tash-Murkon", + "Hibi": "Tash-Murkon", + "Gemodi": "Tash-Murkon", + "Chamume": "Tash-Murkon", + "Nuzair": "Tash-Murkon", + "Pera": "Tash-Murkon", + "Shousran": "Tash-Murkon", + "Yong": "Tash-Murkon", + "Pimebeka": "Tash-Murkon", + "Baviasi": "Tash-Murkon", + "Tash-Murkon Prime": "Tash-Murkon", + "Emrayur": "Tash-Murkon", + "Shesha": "Tash-Murkon", + "Hilaban": "Tash-Murkon", + "Sacalan": "Tash-Murkon", + "Mimen": "Tash-Murkon", + "Thashkarai": "Tash-Murkon", + "Atoosh": "Tash-Murkon", + "Unkah": "Tash-Murkon", + "Hoona": "Tash-Murkon", + "Teshkat": "Tash-Murkon", + "Keshirou": "Tash-Murkon", + "Nasesharafa": "Tash-Murkon", + "Tirbam": "Tash-Murkon", + "Ordat": "Tash-Murkon", + "Rethan": "Tash-Murkon", + "Lossa": "Tash-Murkon", + "Onazel": "Tash-Murkon", + "Asesamy": "Tash-Murkon", + "Hostni": "Tash-Murkon", + "Mimime": "Tash-Murkon", + "Kibursha": "Tash-Murkon", + "Perdan": "Tash-Murkon", + "Abai": "Tash-Murkon", + "Nehkiah": "Tash-Murkon", + "Iro": "Tash-Murkon", + "Ahkour": "Tash-Murkon", + "Gaknem": "Tash-Murkon", + "Siyi": "Tash-Murkon", + "Remoriu": "Tash-Murkon", + "Yanuel": "Tash-Murkon", + "Nafrivik": "Tash-Murkon", + "Taru": "Tash-Murkon", + "Arkoz": "Tash-Murkon", + "Azhgabid": "Tash-Murkon", + "Jinizu": "Tash-Murkon", + "Phoren": "Tash-Murkon", + "Asezai": "Tash-Murkon", + "Ferira": "Tash-Murkon", + "Yeder": "Tash-Murkon", + "Azerakish": "Tash-Murkon", + "Lari": "Tash-Murkon", + "Yasud": "Tash-Murkon", + "Ghishul": "Tash-Murkon", + "Moutid": "Tash-Murkon", + "Goni": "Tash-Murkon", + "Adar": "Tash-Murkon", + "Paye": "Tash-Murkon", + "Sagain": "Tash-Murkon", + "Modun": "Tash-Murkon", + "Saminer": "Tash-Murkon", + "Marthia": "Tash-Murkon", + "Assiad": "Tash-Murkon", + "Rumida": "Tash-Murkon", + "Nosodnis": "Tash-Murkon", + "Iswa": "Tash-Murkon", + "Rand": "Tash-Murkon", + "Sizamod": "Tash-Murkon", + "Sinid": "Tash-Murkon", + "Alra": "Tash-Murkon", + "Ilas": "Tash-Murkon", + "Zith": "Tash-Murkon", + "Tew": "Tash-Murkon", + "Zehru": "Tash-Murkon", + "Uhodoh": "Tash-Murkon", + "Esa": "Tash-Murkon", + "Hath": "Tash-Murkon", + "Judra": "Tash-Murkon", + "Sharios": "Tash-Murkon", + "Arakor": "Tash-Murkon", + "Ahteer": "Tash-Murkon", + "Kari": "Tash-Murkon", + "Kerepa": "Tash-Murkon", + "Pasha": "Tash-Murkon", + "Safilbab": "Tash-Murkon", + "Seitam": "Tash-Murkon", + "JUE-DX": "Outer Passage", + "HLR-GL": "Outer Passage", + "80G-H5": "Outer Passage", + "2EV-BA": "Outer Passage", + "M1-PX9": "Outer Passage", + "W9-TFD": "Outer Passage", + "QHH-13": "Outer Passage", + "J4AQ-O": "Outer Passage", + "O-O2GN": "Outer Passage", + "I-HRX3": "Outer Passage", + "XUPK-Z": "Outer Passage", + "M4U-EH": "Outer Passage", + "WK2F-Y": "Outer Passage", + "WIO-OL": "Outer Passage", + "1-10QG": "Outer Passage", + "YQM-P1": "Outer Passage", + "6-GRN7": "Outer Passage", + "TFPT-U": "Outer Passage", + "D-JVGJ": "Outer Passage", + "K4UV-G": "Outer Passage", + "Q7E-DU": "Outer Passage", + "9Z-XJN": "Outer Passage", + "ZEZ1-9": "Outer Passage", + "QFRV-2": "Outer Passage", + "HZID-J": "Outer Passage", + "8-AA98": "Outer Passage", + "EZWQ-X": "Outer Passage", + "2ULC-J": "Outer Passage", + "T0DT-T": "Outer Passage", + "QG3-Z0": "Outer Passage", + "RT64-C": "Outer Passage", + "2ID-87": "Outer Passage", + "FVQF-W": "Outer Passage", + "8K-QCZ": "Outer Passage", + "JBUH-H": "Outer Passage", + "XDTW-F": "Outer Passage", + "0-4VQL": "Outer Passage", + "SN-DZ6": "Outer Passage", + "DJ-GBH": "Outer Passage", + "I0N-BM": "Outer Passage", + "QOK-SX": "Outer Passage", + "24I-FE": "Outer Passage", + "4H-YJZ": "Outer Passage", + "2-84WC": "Outer Passage", + "V-SEE6": "Outer Passage", + "U-FQ21": "Outer Passage", + "NHKO-4": "Outer Passage", + "KGCF-5": "Outer Passage", + "Y-UO9U": "Outer Passage", + "XME-SW": "Outer Passage", + "JX-SOA": "Outer Passage", + "VH-9VO": "Outer Passage", + "P-T9VC": "Outer Passage", + "9S-GPT": "Outer Passage", + "UAJ5-K": "Outer Passage", + "XJ-AG7": "Outer Passage", + "2WU-XT": "Outer Passage", + "J7X-VN": "Outer Passage", + "F-WCLC": "Outer Passage", + "G-HE0N": "Outer Passage", + "YC-ANK": "Outer Passage", + "LTT-AP": "Outer Passage", + "8RL-OG": "Outer Passage", + "R3P0-Z": "Outer Passage", + "ZZK-VF": "Outer Passage", + "SN-Q1T": "Outer Passage", + "L1YK-V": "Outer Passage", + "ZJ-5IS": "Outer Passage", + "GA58-7": "Outer Passage", + "J-0KB3": "Outer Passage", + "UC-8XF": "Outer Passage", + "90-A1P": "Outer Passage", + "4AZV-W": "Outer Passage", + "UNV-3J": "Outer Passage", + "7F-2FB": "Outer Passage", + "MC4C-H": "Outer Passage", + "OW-QXW": "Outer Passage", + "3-QNM4": "Outer Passage", + "UEPO-D": "Outer Passage", + "NQ-M6W": "Outer Passage", + "P-8PDJ": "Outer Passage", + "VE-W7O": "Outer Passage", + "CNHV-M": "Outer Passage", + "NEU-UD": "Outer Passage", + "N-I024": "Outer Passage", + "4O-ZRI": "Outer Passage", + "Y-7XVJ": "Outer Passage", + "RQNF-9": "Outer Passage", + "DSS-EZ": "Stain", + "MB4D-4": "Stain", + "LGK-VP": "Stain", + "E-C0SR": "Stain", + "X1E-OQ": "Stain", + "VTGN-U": "Stain", + "0Y1-M7": "Stain", + "Q-Q2S6": "Stain", + "WHG2-7": "Stain", + "9RQ-L8": "Stain", + "32-GI9": "Stain", + "TG-Z23": "Stain", + "IP-MVJ": "Stain", + "4J-ZC9": "Stain", + "7R5-7R": "Stain", + "Y1-UQ2": "Stain", + "HM-UVD": "Stain", + "G-ME2K": "Stain", + "WNS-7J": "Stain", + "57M7-W": "Stain", + "JS-E8E": "Stain", + "FV-SE8": "Stain", + "FZSW-Y": "Stain", + "UF-KKH": "Stain", + "O5Y3-W": "Stain", + "0GN-VO": "Stain", + "9U6-SV": "Stain", + "4GQ-XQ": "Stain", + "R8-5XF": "Stain", + "2IGP-1": "Stain", + "Z2-QQP": "Stain", + "GDEW-0": "Stain", + "PSJ-10": "Stain", + "2-V0KY": "Stain", + "U-WLT9": "Stain", + "ZG8Q-N": "Stain", + "40GX-P": "Stain", + "37S-KO": "Stain", + "4J9-DK": "Stain", + "A-GPTM": "Stain", + "HQ-TDJ": "Stain", + "WBLF-0": "Stain", + "GDO-7H": "Stain", + "NZG-LF": "Stain", + "UJM-RD": "Stain", + "L0AD-B": "Stain", + "8ZO-CK": "Stain", + "WEQT-K": "Stain", + "8O-OSG": "Stain", + "1H-I12": "Stain", + "D9D-GD": "Stain", + "4A-XJ6": "Stain", + "GU-54G": "Stain", + "7-X3RN": "Stain", + "BF-FVB": "Stain", + "9O-ZTS": "Stain", + "8KQR-O": "Stain", + "F9SX-1": "Stain", + "0G-A25": "Stain", + "WJO0-G": "Stain", + "S91-TI": "Stain", + "V1V-6F": "Stain", + "S-DLKC": "Stain", + "42-UOW": "Stain", + "CBGG-0": "Stain", + "A4UG-O": "Stain", + "W-VXL9": "Stain", + "U2-BJ2": "Stain", + "UKYS-5": "Stain", + "RV5-DW": "Stain", + "KP-FQ1": "Stain", + "RLDS-R": "Stain", + "QM-O7J": "Stain", + "0-7XA8": "Stain", + "X5O1-L": "Stain", + "F-TVAP": "Stain", + "6Y-0TW": "Stain", + "TL-T9Z": "Stain", + "E7-WSY": "Stain", + "B-G1LG": "Stain", + "T-8UOF": "Stain", + "DP-2WP": "Stain", + "MMR-LZ": "Stain", + "I-ME3L": "Stain", + "YE17-R": "Stain", + "T7-JNB": "Stain", + "LB0-A1": "Stain", + "S-BWWQ": "Stain", + "Z-R96X": "Stain", + "J-AYLV": "Stain", + "DABV-N": "Stain", + "ZH-KEV": "Stain", + "LC-1ED": "Stain", + "RPS-0K": "Stain", + "VNPF-7": "Stain", + "CJF-1P": "Stain", + "U6-FCE": "Stain", + "L6B-0N": "Stain", + "Z-XMUC": "Stain", + "6QBH-S": "Stain", + "RRWI-5": "Stain", + "Y-4U62": "Stain", + "EAWE-2": "Stain", + "I-3FET": "Stain", + "QCKK-T": "Stain", + "RP-H66": "Stain", + "JU-UYK": "Stain", + "O-FTHE": "Stain", + "W-Q233": "Stain", + "4XW2-D": "Stain", + "J5NU-K": "Stain", + "EOT-XL": "Stain", + "RVRE-Z": "Stain", + "B-2UL0": "Stain", + "L-A9FS": "Stain", + "OOO-FS": "Stain", + "373Z-7": "Stain", + "JVJ2-N": "Stain", + "2B-3M4": "Stain", + "A-XASO": "Stain", + "5J-UEX": "Stain", + "1H4V-O": "Stain", + "LGL-SD": "Stain", + "A-DZA8": "Stain", + "O-CT8N": "Stain", + "Z-6YQC": "Stain", + "F7-ICZ": "Stain", + "XFBE-T": "Stain", + "T-NNJZ": "Stain", + "DK6W-I": "Stain", + "0T-LIB": "Stain", + "NRT4-U": "Stain", + "KQK1-2": "Pure Blind", + "O-BY0Y": "Pure Blind", + "2D-0SO": "Pure Blind", + "UR-E6D": "Pure Blind", + "X47L-Q": "Pure Blind", + "D7T-C0": "Pure Blind", + "KI-TL0": "Pure Blind", + "EL8-4Q": "Pure Blind", + "JC-YX8": "Pure Blind", + "5-9WNU": "Pure Blind", + "XI-VUF": "Pure Blind", + "N-H32Y": "Pure Blind", + "12YA-2": "Pure Blind", + "BDV3-T": "Pure Blind", + "J-CIJV": "Pure Blind", + "X-7OMU": "Pure Blind", + "CXN1-Z": "Pure Blind", + "KLY-C0": "Pure Blind", + "CL6-ZG": "Pure Blind", + "G95-VZ": "Pure Blind", + "ROIR-Y": "Pure Blind", + "EC-P8R": "Pure Blind", + "EWOK-K": "Pure Blind", + "O-N8XZ": "Pure Blind", + "G-M4I8": "Pure Blind", + "MI6O-6": "Pure Blind", + "L-TS8S": "Pure Blind", + "93PI-4": "Pure Blind", + "ION-FG": "Pure Blind", + "C-H9X7": "Pure Blind", + "A8I-C5": "Pure Blind", + "DK-FXK": "Pure Blind", + "M-76XI": "Pure Blind", + "ZJET-E": "Pure Blind", + "U-INPD": "Pure Blind", + "WW-KGD": "Pure Blind", + "XQ-PXU": "Pure Blind", + "M-YCD4": "Pure Blind", + "Q-5211": "Pure Blind", + "R-2R0G": "Pure Blind", + "CR-AQH": "Pure Blind", + "8S-0E1": "Pure Blind", + "5ZXX-K": "Pure Blind", + "JE-D5U": "Pure Blind", + "2-6TGQ": "Pure Blind", + "OE-9UF": "Pure Blind", + "PFU-LH": "Pure Blind", + "R6XN-9": "Pure Blind", + "3V8-LJ": "Pure Blind", + "B8EN-S": "Pure Blind", + "R-LW2I": "Pure Blind", + "DP-1YE": "Pure Blind", + "4-ABS8": "Pure Blind", + "7RM-N0": "Pure Blind", + "S-MDYI": "Pure Blind", + "ZKYV-W": "Pure Blind", + "F-NMX6": "Pure Blind", + "GA-P6C": "Pure Blind", + "FWA-4V": "Pure Blind", + "RZC-16": "Pure Blind", + "RD-G2R": "Pure Blind", + "UC3H-Y": "Pure Blind", + "6GWE-A": "Pure Blind", + "J-OK0C": "Pure Blind", + "KDV-DE": "Pure Blind", + "MT9Q-S": "Pure Blind", + "B-9C24": "Pure Blind", + "P-2TTL": "Pure Blind", + "7X-VKB": "Pure Blind", + "E-Z2ZX": "Pure Blind", + "RORZ-H": "Pure Blind", + "O-A6YN": "Pure Blind", + "MQ-NPY": "Pure Blind", + "D2-HOS": "Pure Blind", + "Y2-6EA": "Pure Blind", + "TFA0-U": "Pure Blind", + "RQH-MY": "Pure Blind", + "HPS5-C": "Pure Blind", + "DT-TCD": "Pure Blind", + "KU5R-W": "Pure Blind", + "H1-J33": "Pure Blind", + "Y-C3EQ": "Pure Blind", + "OGV-AS": "Pure Blind", + "7D-0SQ": "Pure Blind", + "UI-8ZE": "Pure Blind", + "NS2L-4": "Immensea", + "QI-S9W": "Immensea", + "B-S347": "Immensea", + "PPFB-U": "Immensea", + "AF0-V5": "Immensea", + "B-A587": "Immensea", + "Y19P-1": "Immensea", + "B9E-H6": "Immensea", + "SPBS-6": "Immensea", + "JDAS-0": "Immensea", + "A4B-V5": "Immensea", + "LN-56V": "Immensea", + "Y2-QUV": "Immensea", + "O7-7UX": "Immensea", + "Z8-81T": "Immensea", + "XD-JW7": "Immensea", + "DY-P7Q": "Immensea", + "H-RXNZ": "Immensea", + "ZBP-TP": "Immensea", + "XVV-21": "Immensea", + "GXK-7F": "Immensea", + "EA-HSA": "Immensea", + "78TS-Q": "Immensea", + "WYF8-8": "Immensea", + "CJNF-J": "Immensea", + "FYI-49": "Immensea", + "RF6T-8": "Immensea", + "ZJA-6U": "Immensea", + "94FR-S": "Immensea", + "Q-HJ97": "Immensea", + "GM-0K7": "Immensea", + "I-NGI8": "Immensea", + "R-ZUOL": "Immensea", + "E1F-LK": "Immensea", + "Z4-QLD": "Immensea", + "QE-E1D": "Immensea", + "LK1K-5": "Immensea", + "REB-KR": "Immensea", + "Z-H2MA": "Immensea", + "L-5JCJ": "Immensea", + "B-KDOZ": "Immensea", + "4-GB14": "Immensea", + "PH-NFR": "Immensea", + "DW-N2S": "Immensea", + "W-FHWJ": "Immensea", + "X-6WC7": "Immensea", + "D-BAMJ": "Immensea", + "JKWP-U": "Immensea", + "RHE7-W": "Immensea", + "F76-8Q": "Immensea", + "O3Z5-G": "Immensea", + "4DV-1T": "Immensea", + "XS-K1O": "Immensea", + "FN-DSR": "Immensea", + "B-R5RB": "Immensea", + "7-ZT1Y": "Immensea", + "9-XN3F": "Immensea", + "AC-7LZ": "Immensea", + "LBA-SO": "Immensea", + "Y-FZ5N": "Immensea", + "E8-YS9": "Immensea", + "U79-JF": "Immensea", + "B2-UQW": "Immensea", + "U9U-TQ": "Immensea", + "6-I162": "Immensea", + "08-N7Q": "Immensea", + "Y-C4AL": "Immensea", + "CKX-RW": "Immensea", + "8X6T-8": "Immensea", + "W4E-IT": "Immensea", + "OP9L-F": "Immensea", + "J-QA7I": "Immensea", + "2O-EEW": "Immensea", + "Y-N4EF": "Immensea", + "7YSF-E": "Immensea", + "KCDX-7": "Immensea", + "O7-VJ5": "Immensea", + "FRTC-5": "Immensea", + "M-ZJWJ": "Immensea", + "R-ORB7": "Immensea", + "RU-PT9": "Immensea", + "DR-427": "Immensea", + "NI-J0B": "Immensea", + "QN-6J2": "Immensea", + "2G-VDP": "Etherium Reach", + "9F-3CR": "Etherium Reach", + "J7M-3W": "Etherium Reach", + "KRPF-A": "Etherium Reach", + "9P-870": "Etherium Reach", + "QNXJ-M": "Etherium Reach", + "AID-9T": "Etherium Reach", + "PXE-RG": "Etherium Reach", + "5J-62N": "Etherium Reach", + "Z-DRIY": "Etherium Reach", + "8-MXHA": "Etherium Reach", + "LPVL-5": "Etherium Reach", + "D3S-EA": "Etherium Reach", + "KGT3-6": "Etherium Reach", + "4LJ6-Q": "Etherium Reach", + "SAH-AD": "Etherium Reach", + "MF-PGF": "Etherium Reach", + "L-ZJLN": "Etherium Reach", + "G-QTSD": "Etherium Reach", + "3G-LFX": "Etherium Reach", + "NK-VTL": "Etherium Reach", + "D-CR6W": "Etherium Reach", + "BY-7PY": "Etherium Reach", + "GN-TNT": "Etherium Reach", + "QKCU-4": "Etherium Reach", + "0M-24X": "Etherium Reach", + "N06Z-Q": "Etherium Reach", + "YX-0KH": "Etherium Reach", + "KMH-J1": "Etherium Reach", + "CYB-BZ": "Etherium Reach", + "5U-3PW": "Etherium Reach", + "89JS-J": "Etherium Reach", + "C9R-NO": "Etherium Reach", + "FKR-SR": "Etherium Reach", + "1ACJ-6": "Etherium Reach", + "BNX-AS": "Etherium Reach", + "XB-9U2": "Etherium Reach", + "F9-FUV": "Etherium Reach", + "FB-MPY": "Etherium Reach", + "RO-0PZ": "Etherium Reach", + "JTA2-2": "Etherium Reach", + "R-6KYM": "Etherium Reach", + "3H58-R": "Etherium Reach", + "RV-GA8": "Etherium Reach", + "TP-RTO": "Etherium Reach", + "GTY-FW": "Etherium Reach", + "1H5-3W": "Etherium Reach", + "QZV-X3": "Etherium Reach", + "IS-OBW": "Etherium Reach", + "1GH-48": "Etherium Reach", + "IRD-HU": "Etherium Reach", + "B-2VXB": "Etherium Reach", + "FIZU-X": "Etherium Reach", + "JAWX-R": "Etherium Reach", + "Z0G-XG": "Etherium Reach", + "ALC-JM": "Etherium Reach", + "9QS5-C": "Etherium Reach", + "NWX-LI": "Etherium Reach", + "N-SFZK": "Etherium Reach", + "2B-UUQ": "Etherium Reach", + "I64-XB": "Etherium Reach", + "4-QDIX": "Etherium Reach", + "FGJP-J": "Etherium Reach", + "89-JPE": "Etherium Reach", + "D-IZT9": "Etherium Reach", + "WU9-ZR": "Etherium Reach", + "E8-432": "Etherium Reach", + "43-1TL": "Etherium Reach", + "O-LJOO": "Etherium Reach", + "ZS-PNI": "Etherium Reach", + "TZ-74M": "Etherium Reach", + "8KE-YS": "Etherium Reach", + "LXQ2-T": "Etherium Reach", + "HV-EAP": "Etherium Reach", + "3IK-7O": "Etherium Reach", + "O-EUHA": "Etherium Reach", + "MO-I1W": "Etherium Reach", + "ZZ5X-M": "Etherium Reach", + "UAV-1E": "Etherium Reach", + "CL-IRS": "Etherium Reach", + "QBZO-R": "Etherium Reach", + "QHJR-E": "Etherium Reach", + "1PF-BC": "Etherium Reach", + "D-OJEZ": "Etherium Reach", + "C-V6DQ": "Etherium Reach", + "Z-FET0": "Etherium Reach", + "EX-GBT": "Etherium Reach", + "PX-IHN": "Etherium Reach", + "WPV-JN": "Etherium Reach", + "IL-H0A": "Etherium Reach", + "CT8K-0": "Etherium Reach", + "M9-LAN": "Etherium Reach", + "C-4D0W": "Etherium Reach", + "L4X-1V": "Etherium Reach", + "M-V0PQ": "Etherium Reach", + "DYPL-6": "Etherium Reach", + "V-OL61": "Etherium Reach", + "RK-Q51": "Etherium Reach", + "F69O-M": "Etherium Reach", + "T-IDGH": "Etherium Reach", + "Aeddin": "Molden Heath", + "Gulfonodi": "Molden Heath", + "Teonusude": "Molden Heath", + "Gelfiven": "Molden Heath", + "Bosena": "Molden Heath", + "Oddelulf": "Molden Heath", + "Atlar": "Molden Heath", + "Heild": "Molden Heath", + "Hrokkur": "Molden Heath", + "Hrober": "Molden Heath", + "Aedald": "Molden Heath", + "Muttokon": "Molden Heath", + "Audesder": "Molden Heath", + "Illamur": "Molden Heath", + "Horaka": "Molden Heath", + "Eldulf": "Molden Heath", + "Orien": "Molden Heath", + "Varigne": "Molden Heath", + "Meildolf": "Molden Heath", + "Istodard": "Molden Heath", + "Gonheim": "Molden Heath", + "Half": "Molden Heath", + "Sakulda": "Molden Heath", + "Hedaleolfarber": "Molden Heath", + "Altbrard": "Molden Heath", + "Fegomenko": "Molden Heath", + "Osvetur": "Molden Heath", + "Mimiror": "Molden Heath", + "Skarkon": "Molden Heath", + "Ennur": "Molden Heath", + "Unertek": "Molden Heath", + "Klingt": "Molden Heath", + "Weld": "Molden Heath", + "Kattegaud": "Molden Heath", + "Kadlina": "Molden Heath", + "Hegfunden": "Molden Heath", + "Aeditide": "Molden Heath", + "Egbinger": "Molden Heath", + "MR4-MY": "Geminate", + "SR-KBB": "Geminate", + "FDZ4-A": "Geminate", + "2E-ZR5": "Geminate", + "O1-FTD": "Geminate", + "Roua": "Geminate", + "OEY-OR": "Geminate", + "M-MD31": "Geminate", + "WH-2EZ": "Geminate", + "D0-F4W": "Geminate", + "QKTR-L": "Geminate", + "YN3-E3": "Geminate", + "NBPH-N": "Geminate", + "L-HV5C": "Geminate", + "L4X-FH": "Geminate", + "B6-52M": "Geminate", + "V-MZW0": "Geminate", + "BND-16": "Geminate", + "IOO-7O": "Geminate", + "BWF-ZZ": "Geminate", + "4-CUM5": "Geminate", + "8MG-J6": "Geminate", + "RLSI-V": "Geminate", + "39-DGG": "Geminate", + "SV-K8J": "Geminate", + "6RQ9-A": "Geminate", + "K42-IE": "Geminate", + "VSJ-PP": "Geminate", + "3USX-F": "Geminate", + "9-KWXC": "Geminate", + "NQ-9IH": "Geminate", + "KR-V6G": "Geminate", + "AP9-LV": "Geminate", + "0-GZX9": "Geminate", + "2H-TSE": "Geminate", + "4NGK-F": "Geminate", + "O-VWPB": "Geminate", + "LX-ZOJ": "Geminate", + "6L78-1": "Geminate", + "04-LQM": "Geminate", + "4VY-Y1": "Geminate", + "LU-HQS": "Geminate", + "U-L4KS": "Geminate", + "K25-XD": "Geminate", + "6YC-TU": "Geminate", + "Y8R-XZ": "Geminate", + "P-E9GN": "Geminate", + "HJO-84": "Geminate", + "4D9-66": "Geminate", + "L-TOFR": "Geminate", + "Q-TBHW": "Geminate", + "9P4O-F": "Geminate", + "UBX-CC": "Geminate", + "TJM-JJ": "Geminate", + "EOA-ZC": "Geminate", + "G-73MR": "Geminate", + "E-91FV": "Geminate", + "AD-5B8": "Geminate", + "QP0K-B": "Geminate", + "54-MF6": "Geminate", + "D-I9HJ": "Geminate", + "P-6I0B": "Geminate", + "CFYY-J": "Geminate", + "8-KZXQ": "Geminate", + "HKYW-T": "Geminate", + "3SFU-S": "Geminate", + "VJ-NQP": "Geminate", + "U6D-9A": "Geminate", + "Atioth": "Geminate", + "PYY3-5": "Geminate", + "RFGW-V": "Geminate", + "N-HK93": "Geminate", + "LR-2XT": "Geminate", + "TZL-WT": "Geminate", + "4K0N-J": "Geminate", + "B-F1MI": "Geminate", + "W-3BSU": "Geminate", + "BE-UUN": "Geminate", + "O2O-2X": "Geminate", + "JE1-36": "Geminate", + "5F-YRA": "Geminate", + "TDE4-H": "Geminate", + "UER-TH": "Geminate", + "UG-UWZ": "Geminate", + "Hulm": "Heimatar", + "Osoggur": "Heimatar", + "Abudban": "Heimatar", + "Trytedald": "Heimatar", + "Odatrik": "Heimatar", + "Rens": "Heimatar", + "Ameinaka": "Heimatar", + "Alakgur": "Heimatar", + "Dammalin": "Heimatar", + "Bosboger": "Heimatar", + "Olfeim": "Heimatar", + "Lulm": "Heimatar", + "Gulmorogod": "Heimatar", + "Edmalbrurdus": "Heimatar", + "Kronsur": "Heimatar", + "Dumkirinur": "Heimatar", + "Sist": "Heimatar", + "Obrolber": "Heimatar", + "Austraka": "Heimatar", + "Ivar": "Heimatar", + "Meirakulf": "Heimatar", + "Frarn": "Heimatar", + "Illinfrik": "Heimatar", + "Balginia": "Heimatar", + "Gyng": "Heimatar", + "Avesber": "Heimatar", + "Gerek": "Heimatar", + "Tongofur": "Heimatar", + "Gerbold": "Heimatar", + "Rokofur": "Heimatar", + "Ebasgerdur": "Heimatar", + "Ebodold": "Heimatar", + "Amamake": "Heimatar", + "Vard": "Heimatar", + "Siseide": "Heimatar", + "Lantorn": "Heimatar", + "Dal": "Heimatar", + "Auga": "Heimatar", + "Eystur": "Heimatar", + "Pator": "Heimatar", + "Lustrevik": "Heimatar", + "Isendeldik": "Heimatar", + "Ammold": "Heimatar", + "Emolgranlan": "Heimatar", + "Offugen": "Heimatar", + "Roniko": "Heimatar", + "Aralgrund": "Heimatar", + "Eddar": "Heimatar", + "Bogelek": "Heimatar", + "Wiskeber": "Heimatar", + "Eifer": "Heimatar", + "Gusandall": "Heimatar", + "Atgur": "Heimatar", + "Endrulf": "Heimatar", + "Ingunn": "Heimatar", + "Gultratren": "Heimatar", + "Auren": "Heimatar", + "Trer": "Heimatar", + "Egmur": "Heimatar", + "Javrendei": "Heimatar", + "Appen": "Heimatar", + "Klir": "Heimatar", + "Jorus": "Heimatar", + "Onga": "Heimatar", + "Osaumuni": "Heimatar", + "Magiko": "Heimatar", + "Oremmulf": "Heimatar", + "Hurjafren": "Heimatar", + "Vullat": "Heimatar", + "Hrondedir": "Heimatar", + "Sotrenzur": "Heimatar", + "Hrondmund": "Heimatar", + "Bundindus": "Heimatar", + "Otraren": "Heimatar", + "Hedgiviter": "Heimatar", + "Katugumur": "Heimatar", + "Malukker": "Heimatar", + "Hadaugago": "Heimatar", + "Krilmokenur": "Heimatar", + "Todeko": "Heimatar", + "Larkugei": "Heimatar", + "Usteli": "Heimatar", + "Loguttur": "Heimatar", + "1-7KWU": "Impass", + "3-UCBF": "Impass", + "N-CREL": "Impass", + "TM-0P2": "Impass", + "4OIV-X": "Impass", + "Y-JKJ8": "Impass", + "AFJ-NB": "Impass", + "H-64KI": "Impass", + "9I-SRF": "Impass", + "9-IIBL": "Impass", + "5GQ-S9": "Impass", + "YALR-F": "Impass", + "68FT-6": "Impass", + "IV-UNR": "Impass", + "IRE-98": "Impass", + "HOHF-B": "Impass", + "Y-6B0E": "Impass", + "F-3H2P": "Impass", + "DY-40Z": "Impass", + "XWY-YM": "Impass", + "M-9V5D": "Impass", + "O2-39S": "Impass", + "M-VEJZ": "Impass", + "LJK-T0": "Impass", + "E7VE-V": "Impass", + "NUG-OF": "Impass", + "L6BY-P": "Impass", + "U3SQ-X": "Impass", + "01TG-J": "Impass", + "UK-SHL": "Impass", + "A1BK-A": "Impass", + "N-7ECY": "Impass", + "4-MPSJ": "Impass", + "TWJ-AW": "Impass", + "PZMA-E": "Impass", + "442-CS": "Impass", + "Z-N9IP": "Impass", + "9ZFH-Z": "Impass", + "6E-MOW": "Impass", + "GBT4-J": "Impass", + "GZ1-A1": "Impass", + "X-0CKQ": "Impass", + "6B-GKA": "Impass", + "LHGA-W": "Impass", + "4RS-L1": "Impass", + "D-L4H0": "Impass", + "GU-9F4": "Impass", + "FG-1GH": "Impass", + "WFYM-0": "Impass", + "FR-B1H": "Impass", + "DDI-B7": "Impass", + "Pettinck": "Sinq Laison", + "Du Annes": "Sinq Laison", + "Balle": "Sinq Laison", + "Decon": "Sinq Laison", + "Grinacanne": "Sinq Laison", + "Metserel": "Sinq Laison", + "Sharuveil": "Sinq Laison", + "Adreland": "Sinq Laison", + "Erme": "Sinq Laison", + "Aufay": "Sinq Laison", + "Iyen-Oursta": "Sinq Laison", + "Faurent": "Sinq Laison", + "Ambeke": "Sinq Laison", + "Carrou": "Sinq Laison", + "Direrie": "Sinq Laison", + "Ignoitton": "Sinq Laison", + "Ardene": "Sinq Laison", + "Boillair": "Sinq Laison", + "Ney": "Sinq Laison", + "Fasse": "Sinq Laison", + "Ala": "Sinq Laison", + "Gratesier": "Sinq Laison", + "Schoorasana": "Sinq Laison", + "Vylade": "Sinq Laison", + "Auvergne": "Sinq Laison", + "Aunia": "Sinq Laison", + "Agrallarier": "Sinq Laison", + "Dodixie": "Sinq Laison", + "Eglennaert": "Sinq Laison", + "Botane": "Sinq Laison", + "Pulin": "Sinq Laison", + "Foves": "Sinq Laison", + "Alles": "Sinq Laison", + "Misneden": "Sinq Laison", + "Basgerin": "Sinq Laison", + "Chelien": "Sinq Laison", + "Trosquesere": "Sinq Laison", + "Ansone": "Sinq Laison", + "Dunraelare": "Sinq Laison", + "Nausschie": "Sinq Laison", + "Inghenges": "Sinq Laison", + "Estene": "Sinq Laison", + "Gallareue": "Sinq Laison", + "Stayme": "Sinq Laison", + "Parchanier": "Sinq Laison", + "Fluekele": "Sinq Laison", + "Alsottobier": "Sinq Laison", + "Jolia": "Sinq Laison", + "Augnais": "Sinq Laison", + "Deltole": "Sinq Laison", + "Colelie": "Sinq Laison", + "Barmalie": "Sinq Laison", + "Audaerne": "Sinq Laison", + "Dodenvale": "Sinq Laison", + "Olettiers": "Sinq Laison", + "Artisine": "Sinq Laison", + "Chainelant": "Sinq Laison", + "Sileperer": "Sinq Laison", + "Bamiette": "Sinq Laison", + "Crielere": "Sinq Laison", + "Jel": "Sinq Laison", + "Egghelende": "Sinq Laison", + "Odette": "Sinq Laison", + "Ation": "Sinq Laison", + "Stegette": "Sinq Laison", + "Ravarin": "Sinq Laison", + "Aliette": "Sinq Laison", + "Brapelille": "Sinq Laison", + "Bawilan": "Sinq Laison", + "Atier": "Sinq Laison", + "Archee": "Sinq Laison", + "Brybier": "Sinq Laison", + "Adrallezoen": "Sinq Laison", + "Croleur": "Sinq Laison", + "Doussivitte": "Sinq Laison", + "Unel": "Sinq Laison", + "Claysson": "Sinq Laison", + "Auberulle": "Sinq Laison", + "Adiere": "Sinq Laison", + "Stetille": "Sinq Laison", + "Alillere": "Sinq Laison", + "Abenync": "Sinq Laison", + "Pozirblant": "Sinq Laison", + "Bourynes": "Sinq Laison", + "Aurcel": "Sinq Laison", + "Aymaerne": "Sinq Laison", + "Rancer": "Sinq Laison", + "Miroitem": "Sinq Laison", + "Thelan": "Sinq Laison", + "Rorsins": "Sinq Laison", + "Lamadent": "Sinq Laison", + "Otou": "Sinq Laison", + "Assiettes": "Sinq Laison", + "Goinard": "Sinq Laison", + "Raeghoscon": "Sinq Laison", + "Allipes": "Sinq Laison", + "Lermireve": "Sinq Laison", + "Aetree": "Sinq Laison", + "Esmes": "Sinq Laison", + "Vittenyn": "Sinq Laison", + "Mirilene": "Sinq Laison", + "Pucherie": "Sinq Laison", + "Fricoure": "Sinq Laison", + "Caretyn": "Sinq Laison", + "Ainaille": "Sinq Laison", + "Odotte": "Sinq Laison", + "Oirtlair": "Sinq Laison", + "Olelon": "Sinq Laison", + "Trossere": "Sinq Laison", + "Konola": "The Citadel", + "Inoue": "The Citadel", + "Isaziwa": "The Citadel", + "Eitu": "The Citadel", + "Horkkisen": "The Citadel", + "Erila": "The Citadel", + "Ohvosamon": "The Citadel", + "Auviken": "The Citadel", + "Saikanen": "The Citadel", + "Oijamon": "The Citadel", + "Kakki": "The Citadel", + "Jeras": "The Citadel", + "Kausaaja": "The Citadel", + "Oiniken": "The Citadel", + "Kaimon": "The Citadel", + "Ahynada": "The Citadel", + "Aikoro": "The Citadel", + "Alikara": "The Citadel", + "Usi": "The Citadel", + "Ishomilken": "The Citadel", + "Nikkishina": "The Citadel", + "Hasama": "The Citadel", + "Uuna": "The Citadel", + "Manjonakko": "The Citadel", + "Kassigainen": "The Citadel", + "Yashunen": "The Citadel", + "Tennen": "The Citadel", + "Hatakani": "The Citadel", + "Sivala": "The Citadel", + "Iivinen": "The Citadel", + "Kubinen": "The Citadel", + "Uedama": "The Citadel", + "Enderailen": "The Citadel", + "Tunudan": "The Citadel", + "Kulelen": "The Citadel", + "Rairomon": "The Citadel", + "Hogimo": "The Citadel", + "Huttaken": "The Citadel", + "Paara": "The Citadel", + "Annaro": "The Citadel", + "Isutaka": "The Citadel", + "Tasabeshi": "The Citadel", + "Ono": "The Citadel", + "Muvolailen": "The Citadel", + "Halaima": "The Citadel", + "Kamio": "The Citadel", + "Sankkasen": "The Citadel", + "Tintoh": "The Citadel", + "Santola": "The Citadel", + "Ikao": "The Citadel", + "Waira": "The Citadel", + "Inaro": "The Citadel", + "Kaaputenen": "The Citadel", + "Waskisen": "The Citadel", + "Sirppala": "The Citadel", + "Irjunen": "The Citadel", + "Inari": "The Citadel", + "Yria": "The Citadel", + "Oshaima": "The Citadel", + "Hysera": "The Citadel", + "Kaunokka": "The Citadel", + "Venilen": "The Citadel", + "Oisio": "The Citadel", + "Haatomo": "The Citadel", + "Suroken": "The Citadel", + "Kusomonmon": "The Citadel", + "Juunigaishi": "The Citadel", + "Isikesu": "The Citadel", + "Anttiri": "The Citadel", + "Hasmijaala": "The Citadel", + "Nagamanen": "The Citadel", + "Oto": "The Citadel", + "Sujarento": "The Citadel", + "Eranakko": "The Citadel", + "Onatoh": "The Citadel", + "Tannolen": "The Citadel", + "Tama": "The Citadel", + "Uotila": "The Citadel", + "Isenairos": "The Citadel", + "Saila": "The Citadel", + "Aramachi": "The Citadel", + "Oichiya": "The Citadel", + "Motsu": "The Citadel", + "Komo": "The Citadel", + "Urhinichi": "The Citadel", + "Laah": "The Citadel", + "N-JK02": "The Kalevala Expanse", + "JT2I-7": "The Kalevala Expanse", + "XTJ-5Q": "The Kalevala Expanse", + "1-KCSA": "The Kalevala Expanse", + "UJXC-B": "The Kalevala Expanse", + "UDVW-O": "The Kalevala Expanse", + "F48K-D": "The Kalevala Expanse", + "FBH-JN": "The Kalevala Expanse", + "BVRQ-O": "The Kalevala Expanse", + "QX-4HO": "The Kalevala Expanse", + "LS3-HP": "The Kalevala Expanse", + "SH6X-F": "The Kalevala Expanse", + "6V-D0E": "The Kalevala Expanse", + "SG-3HY": "The Kalevala Expanse", + "AU2V-J": "The Kalevala Expanse", + "SY-0AM": "The Kalevala Expanse", + "A-YB15": "The Kalevala Expanse", + "QZX-L9": "The Kalevala Expanse", + "D-6PKO": "The Kalevala Expanse", + "RAI-0E": "The Kalevala Expanse", + "MN9P-A": "The Kalevala Expanse", + "TA9T-P": "The Kalevala Expanse", + "L-TLFU": "The Kalevala Expanse", + "BM-VYZ": "The Kalevala Expanse", + "Q-GICU": "The Kalevala Expanse", + "EPCD-D": "The Kalevala Expanse", + "0S1-GI": "The Kalevala Expanse", + "L-GY1B": "The Kalevala Expanse", + "74-DRC": "The Kalevala Expanse", + "LE-67X": "The Kalevala Expanse", + "B1UE-J": "The Kalevala Expanse", + "O31W-6": "The Kalevala Expanse", + "M3-H2Y": "The Kalevala Expanse", + "G-KCFT": "The Kalevala Expanse", + "WNM-V0": "The Kalevala Expanse", + "6FS-CZ": "The Kalevala Expanse", + "HPV-RJ": "The Kalevala Expanse", + "H7S-5I": "The Kalevala Expanse", + "C3J0-O": "The Kalevala Expanse", + "GSO-SR": "The Kalevala Expanse", + "B3ZU-H": "The Kalevala Expanse", + "G4-QU6": "The Kalevala Expanse", + "V2-GZS": "The Kalevala Expanse", + "HD-HOZ": "The Kalevala Expanse", + "42G-OB": "The Kalevala Expanse", + "LEM-I1": "The Kalevala Expanse", + "1S-SU1": "The Kalevala Expanse", + "ND-GL4": "The Kalevala Expanse", + "9-0QB7": "The Kalevala Expanse", + "M-75WN": "The Kalevala Expanse", + "PNFW-O": "The Kalevala Expanse", + "HVGR-R": "The Kalevala Expanse", + "K76A-3": "The Kalevala Expanse", + "K95-9I": "The Kalevala Expanse", + "R1O-GN": "The Kalevala Expanse", + "GQ-7SP": "The Kalevala Expanse", + "BGMZ-0": "The Kalevala Expanse", + "I2D3-5": "The Kalevala Expanse", + "FZX-PU": "The Kalevala Expanse", + "O9K-FT": "The Kalevala Expanse", + "RQOO-U": "The Kalevala Expanse", + "FB5U-I": "The Kalevala Expanse", + "BZ-BCK": "The Kalevala Expanse", + "5-VFC6": "The Kalevala Expanse", + "O5-YNW": "The Kalevala Expanse", + "86L-9F": "The Kalevala Expanse", + "IUU3-L": "The Kalevala Expanse", + "J-OAH2": "The Kalevala Expanse", + "S-LHPJ": "The Kalevala Expanse", + "4U90-Z": "Deklein", + "T-945F": "Deklein", + "FO8M-2": "Deklein", + "AD-CBT": "Deklein", + "QPO-WI": "Deklein", + "R8S-1K": "Deklein", + "94-H3F": "Deklein", + "CU9-T0": "Deklein", + "XCF-8N": "Deklein", + "FMB-JP": "Deklein", + "0P-F3K": "Deklein", + "K5F-Z2": "Deklein", + "TXME-A": "Deklein", + "YA0-XJ": "Deklein", + "2-KF56": "Deklein", + "VFK-IV": "Deklein", + "2R-CRW": "Deklein", + "CCP-US": "Deklein", + "II-5O9": "Deklein", + "I30-3A": "Deklein", + "2O9G-D": "Deklein", + "NC-N3F": "Deklein", + "JU-OWQ": "Deklein", + "S-DN5M": "Deklein", + "MXX5-9": "Deklein", + "ZZZR-5": "Deklein", + "C7Y-7Z": "Deklein", + "X-Z4DA": "Deklein", + "3OAT-Q": "Deklein", + "N-TFXK": "Deklein", + "33RB-O": "Deklein", + "DKUK-G": "Deklein", + "3QE-9Q": "Deklein", + "E-FIC0": "Deklein", + "ZOYW-O": "Deklein", + "85-B52": "Deklein", + "YZ-UKA": "Deklein", + "RO0-AF": "Deklein", + "5W3-DG": "Deklein", + "LT-DRO": "Deklein", + "7T6P-C": "Deklein", + "8S28-3": "Deklein", + "E3UY-6": "Deklein", + "LEK-N5": "Deklein", + "AGG-NR": "Deklein", + "0V0R-R": "Deklein", + "O-2RNZ": "Deklein", + "OWXT-5": "Deklein", + "3JN9-Q": "Deklein", + "3T7-M8": "Deklein", + "WUZ-WM": "Deklein", + "MZ1E-P": "Deklein", + "43B-O1": "Deklein", + "J1AU-9": "Deklein", + "X3-PBC": "Deklein", + "4N-BUI": "Deklein", + "N2IS-B": "Deklein", + "XCBK-X": "Deklein", + "GY5-26": "Deklein", + "VPLL-N": "Deklein", + "9CK-KZ": "Deklein", + "5S-KXA": "Deklein", + "U-TJ7Y": "Deklein", + "A4L-A2": "Deklein", + "CZDJ-1": "Deklein", + "RG9-7U": "Deklein", + "UJY-HE": "Deklein", + "UEJX-G": "Deklein", + "Tzvi": "Devoid", + "Raa": "Devoid", + "Sifilar": "Devoid", + "Arzad": "Devoid", + "Oyeman": "Devoid", + "Ezzara": "Devoid", + "Odin": "Devoid", + "Esescama": "Devoid", + "Choonka": "Devoid", + "Thasinaz": "Devoid", + "Dihra": "Devoid", + "Dital": "Devoid", + "Eredan": "Devoid", + "Ohide": "Devoid", + "Sasoutikh": "Devoid", + "Gheth": "Devoid", + "Lisudeh": "Devoid", + "Mehatoor": "Devoid", + "Roushzar": "Devoid", + "Labapi": "Devoid", + "Arayar": "Devoid", + "Asghed": "Devoid", + "Tararan": "Devoid", + "Sosan": "Devoid", + "Halmah": "Devoid", + "Rahadalon": "Devoid", + "Soosat": "Devoid", + "Ibash": "Devoid", + "Itsyamil": "Devoid", + "Mendori": "Devoid", + "Ussad": "Devoid", + "Nakatre": "Devoid", + "Laddiaha": "Devoid", + "Hakshma": "Devoid", + "Uadelah": "Devoid", + "Akes": "Devoid", + "Riavayed": "Devoid", + "Hati": "Devoid", + "Naeel": "Devoid", + "Lower Debyl": "Devoid", + "Ehnoum": "Devoid", + "Upper Debyl": "Devoid", + "Shastal": "Devoid", + "Thakala": "Devoid", + "Mili": "Devoid", + "Faktun": "Devoid", + "Halenan": "Devoid", + "Ulerah": "Devoid", + "Uktiad": "Devoid", + "Nidebora": "Devoid", + "Arveyil": "Devoid", + "Palpis": "Devoid", + "Arnatele": "Everyshore", + "Halle": "Everyshore", + "Mormoen": "Everyshore", + "Amattens": "Everyshore", + "Jurlesel": "Everyshore", + "Bereye": "Everyshore", + "Aice": "Everyshore", + "Junsoraert": "Everyshore", + "Harerget": "Everyshore", + "Azer": "Everyshore", + "Cherore": "Everyshore", + "Torvi": "Everyshore", + "Mosson": "Everyshore", + "Mya": "Everyshore", + "Gerper": "Everyshore", + "Marosier": "Everyshore", + "Lirsautton": "Everyshore", + "Blameston": "Everyshore", + "Vaurent": "Everyshore", + "Aclan": "Everyshore", + "Jaschercis": "Everyshore", + "Ardallabier": "Everyshore", + "Athinard": "Everyshore", + "Meves": "Everyshore", + "Ethernity": "Everyshore", + "Mattere": "Everyshore", + "Gicodel": "Everyshore", + "Frarolle": "Everyshore", + "Quier": "Everyshore", + "Atlanins": "Everyshore", + "Leremblompes": "Everyshore", + "Bille": "Everyshore", + "Colcer": "Everyshore", + "Alachene": "Everyshore", + "Uphene": "Everyshore", + "Elarel": "Everyshore", + "Enedore": "Everyshore", + "Angymonne": "Everyshore", + "Averon": "Everyshore", + "Carirgnottin": "Everyshore", + "Laic": "Everyshore", + "Odixie": "Everyshore", + "Antollare": "Everyshore", + "Tolle": "Everyshore", + "Avele": "Everyshore", + "Scuelazyns": "Everyshore", + "Aydoteaux": "Everyshore", + "Muer": "Everyshore", + "Groothese": "Everyshore", + "Olide": "Everyshore", + "Adeel": "Everyshore", + "Mannar": "Everyshore", + "Mormelot": "Everyshore", + "Angatalie": "Everyshore", + "Lamaa": "The Bleak Lands", + "Tuomuta": "The Bleak Lands", + "Otelen": "The Bleak Lands", + "Kuomi": "The Bleak Lands", + "Huola": "The Bleak Lands", + "Kourmonen": "The Bleak Lands", + "Kamela": "The Bleak Lands", + "Sosala": "The Bleak Lands", + "Anka": "The Bleak Lands", + "Iesa": "The Bleak Lands", + "Netsalakka": "The Bleak Lands", + "Sasiekko": "The Bleak Lands", + "Myyhera": "The Bleak Lands", + "Gammel": "The Bleak Lands", + "Uusanen": "The Bleak Lands", + "Erkinen": "The Bleak Lands", + "Saikamon": "The Bleak Lands", + "Jarkkolen": "The Bleak Lands", + "Ronne": "The Bleak Lands", + "Hatori": "The Bleak Lands", + "Junsen": "The Bleak Lands", + "Malpara": "The Bleak Lands", + "Hakodan": "The Bleak Lands", + "Sahtogas": "The Bleak Lands", + "Haras": "The Bleak Lands", + "Oyonata": "The Bleak Lands", + "Kurniainen": "The Bleak Lands", + "Saidusairos": "The Bleak Lands", + "Tannakan": "The Bleak Lands", + "Komaa": "The Bleak Lands", + "Ayeroilen": "The Bleak Lands", + "Imata": "The Bleak Lands", + "Furskeshin": "The Bleak Lands", + "Kurmaru": "The Bleak Lands", + "Satalama": "The Bleak Lands", + "VYJ-DA": "Esoteria", + "HHQ-M1": "Esoteria", + "A-CJGE": "Esoteria", + "G2-INZ": "Esoteria", + "WAC-HW": "Esoteria", + "HT4K-M": "Esoteria", + "RBW-8G": "Esoteria", + "4-OUKF": "Esoteria", + "HAJ-DQ": "Esoteria", + "JAUD-V": "Esoteria", + "DTX8-M": "Esoteria", + "C9N-CC": "Esoteria", + "X-7BIX": "Esoteria", + "5-9UXZ": "Esoteria", + "Q0OH-V": "Esoteria", + "C-VZAK": "Esoteria", + "0-O6XF": "Esoteria", + "D-FVI7": "Esoteria", + "VL7-60": "Esoteria", + "NH-R5B": "Esoteria", + "FN-GFQ": "Esoteria", + "XKZ8-H": "Esoteria", + "WX-6UX": "Esoteria", + "BZ-0GW": "Esoteria", + "16P-PX": "Esoteria", + "CR-0E5": "Esoteria", + "Z-Y9C3": "Esoteria", + "A1-AUH": "Esoteria", + "F-UVBV": "Esoteria", + "R-FM0G": "Esoteria", + "TEIZ-C": "Esoteria", + "VUAC-Y": "Esoteria", + "V-XANH": "Esoteria", + "450I-W": "Esoteria", + "OIOM-Y": "Esoteria", + "G-YZUX": "Esoteria", + "CZ6U-1": "Esoteria", + "D-PNP9": "Esoteria", + "E1UU-3": "Esoteria", + "P-3XVV": "Esoteria", + "BY-MSY": "Esoteria", + "6EK-BV": "Esoteria", + "IR-FDV": "Esoteria", + "NIZJ-0": "Esoteria", + "J-RVGD": "Esoteria", + "V1ZC-S": "Esoteria", + "H-T40Z": "Esoteria", + "6-TYRX": "Esoteria", + "Q1-R7K": "Esoteria", + "111-F1": "Esoteria", + "JD-TYH": "Esoteria", + "02V-BK": "Esoteria", + "A5MT-B": "Esoteria", + "R-ARKN": "Esoteria", + "SN9S-N": "Esoteria", + "MS2-V8": "Esoteria", + "Z-MO29": "Esoteria", + "G-JC9R": "Esoteria", + "DIBH-Q": "Esoteria", + "DNEP-Y": "Esoteria", + "YAP-TN": "Esoteria", + "PE-H02": "Esoteria", + "H-YHYM": "Esoteria", + "G-4H4C": "Esoteria", + "HHE5-L": "Esoteria", + "P9F-ZG": "Esoteria", + "QFGB-E": "Esoteria", + "7P-J38": "Esoteria", + "WT-2J9": "Esoteria", + "PK-PHZ": "Esoteria", + "L-M6JK": "Esoteria", + "C-PEWN": "Esoteria", + "DL-CDY": "Esoteria", + "29YH-V": "Esoteria", + "LG-RO2": "Esoteria", + "X-HISR": "Esoteria", + "QS-530": "Esoteria", + "VR-YRV": "Esoteria", + "IPX-H5": "Esoteria", + "KSM-1T": "Esoteria", + "YRV-MZ": "Esoteria", + "6SB-BN": "Esoteria", + "B1D-KU": "Esoteria", + "QFIU-K": "Esoteria", + "2R-KLH": "Esoteria", + "QB-AE6": "Oasa", + "G-W1ND": "Oasa", + "MZLW-9": "Oasa", + "ND-X7X": "Oasa", + "DGDT-3": "Oasa", + "2-WNTD": "Oasa", + "83-YGI": "Oasa", + "KH-EWC": "Oasa", + "3VL6-I": "Oasa", + "F-816R": "Oasa", + "DS3-6A": "Oasa", + "V0-H4L": "Oasa", + "T-HMWP": "Oasa", + "DYS-CG": "Oasa", + "MTGF-2": "Oasa", + "0-QP56": "Oasa", + "GTQ-C9": "Oasa", + "M-NWLB": "Oasa", + "ORB4-J": "Oasa", + "GGMF-J": "Oasa", + "IG-4OF": "Oasa", + "LQQH-J": "Oasa", + "W5-VBR": "Oasa", + "J-D5U7": "Oasa", + "Y-770C": "Oasa", + "X-Z4JW": "Oasa", + "R8WV-7": "Oasa", + "6U-MFQ": "Oasa", + "1EO-OE": "Oasa", + "YQTK-R": "Oasa", + "FZCR-3": "Oasa", + "5-9L3H": "Oasa", + "1-HDQ4": "Oasa", + "WVMS-X": "Oasa", + "7-UVMT": "Oasa", + "R-ZESX": "Oasa", + "IO-R2S": "Oasa", + "HF-K3O": "Oasa", + "QE2-FS": "Oasa", + "Q-ITV5": "Oasa", + "5JEZ-I": "Oasa", + "XEF6-Z": "Oasa", + "SON-TW": "Oasa", + "V-X0KM": "Oasa", + "U9SE-N": "Oasa", + "XXZ-3W": "Oasa", + "RF-X7V": "Oasa", + "BQ0-UU": "Oasa", + "3-JG3X": "Oasa", + "GK3-RX": "Oasa", + "1P-QWR": "Oasa", + "FJ-GUR": "Oasa", + "UGR-J2": "Oasa", + "QZ-DIZ": "Oasa", + "Y-0HVF": "Oasa", + "21M1-B": "Oasa", + "KED-2O": "Oasa", + "U-RELP": "Oasa", + "IAMJ-Q": "Oasa", + "E6Q-LE": "Oasa", + "HO4E-Q": "Oasa", + "QY2Y-N": "Oasa", + "X-9ZZR": "Oasa", + "RO-AIQ": "Oasa", + "VZEG-B": "Oasa", + "P-ZWKH": "Oasa", + "9G5J-1": "Oasa", + "B-ETDW": "Oasa", + "0PU2-R": "Oasa", + "XM-RMD": "Oasa", + "91-KD8": "Oasa", + "OZ-DS5": "Oasa", + "LA2-KV": "Oasa", + "WW-OVQ": "Oasa", + "S7WI-F": "Oasa", + "1-BK1Q": "Oasa", + "X-CYNC": "Oasa", + "RJBC-I": "Oasa", + "H-MHWF": "Oasa", + "PND-SI": "Oasa", + "XKM-DE": "Oasa", + "JXQJ-B": "Oasa", + "Y-BIPM": "Oasa", + "QYT-X8": "Oasa", + "5-IH57": "Oasa", + "MHC-R3": "Syndicate", + "F67E-Q": "Syndicate", + "6E-578": "Syndicate", + "Poitot": "Syndicate", + "ZVN5-H": "Syndicate", + "ATY-2U": "Syndicate", + "X-BV98": "Syndicate", + "2X-PQG": "Syndicate", + "FD-MLJ": "Syndicate", + "PF-346": "Syndicate", + "X-M2LR": "Syndicate", + "K5-JRD": "Syndicate", + "6-CZ49": "Syndicate", + "EZA-FM": "Syndicate", + "8-JYPM": "Syndicate", + "PVH8-0": "Syndicate", + "M2-CF1": "Syndicate", + "JH-M2W": "Syndicate", + "PC9-AY": "Syndicate", + "T22-QI": "Syndicate", + "X-PYH5": "Syndicate", + "ZN0-SR": "Syndicate", + "5-DSFH": "Syndicate", + "AK-QBU": "Syndicate", + "QWF-6P": "Syndicate", + "AAS-8R": "Syndicate", + "V4-L0X": "Syndicate", + "PFP-GU": "Syndicate", + "0EK-NJ": "Syndicate", + "1-NKVT": "Syndicate", + "UM-Q7F": "Syndicate", + "T-LIWS": "Syndicate", + "KTHT-O": "Syndicate", + "97X-CH": "Syndicate", + "5-T0PZ": "Syndicate", + "6R-PWU": "Syndicate", + "2Q-I6Q": "Syndicate", + "A-ZLHX": "Syndicate", + "UTKS-5": "Syndicate", + "Y9G-KS": "Syndicate", + "I-YGGI": "Syndicate", + "VV-VCR": "Syndicate", + "5-75MB": "Syndicate", + "IIRH-G": "Syndicate", + "35-RK9": "Syndicate", + "XS-XAY": "Syndicate", + "DP34-U": "Syndicate", + "617I-I": "Syndicate", + "6-U2M8": "Syndicate", + "I0AB-R": "Syndicate", + "MXYS-8": "Syndicate", + "A-3ES3": "Syndicate", + "8V-SJJ": "Syndicate", + "5-FGQI": "Syndicate", + "3KNK-A": "Syndicate", + "TXW-EI": "Syndicate", + "3MOG-V": "Syndicate", + "NG-C6Y": "Syndicate", + "XYY-IA": "Syndicate", + "BMNV-P": "Syndicate", + "BY-S36": "Syndicate", + "31-MLU": "Syndicate", + "0LTQ-C": "Syndicate", + "A9D-R0": "Syndicate", + "2P-4LS": "Syndicate", + "RF-GGF": "Syndicate", + "LSC4-P": "Syndicate", + "A-SJ8X": "Syndicate", + "10UZ-P": "Syndicate", + "EN-VOD": "Syndicate", + "9GYL-O": "Syndicate", + "VLGD-R": "Syndicate", + "S-GKKR": "Syndicate", + "9U-TTJ": "Syndicate", + "Y-W6GF": "Syndicate", + "KFR-ZE": "Syndicate", + "KLYN-8": "Syndicate", + "D85-VD": "Syndicate", + "5-VKCN": "Syndicate", + "U0V6-T": "Syndicate", + "5KS-AB": "Syndicate", + "0T-AMZ": "Syndicate", + "57-YRU": "Syndicate", + "4L-E5P": "Syndicate", + "UFXF-C": "Syndicate", + "RLL-9R": "Syndicate", + "51-5XG": "Syndicate", + "EF-F36": "Syndicate", + "3-IN0V": "Syndicate", + "Z-QENW": "Syndicate", + "D-B7YK": "Syndicate", + "DUV-5Y": "Syndicate", + "GRNJ-3": "Syndicate", + "VSIG-K": "Syndicate", + "RSS-KA": "Syndicate", + "CIS-7X": "Syndicate", + "DCHR-L": "Syndicate", + "EU0I-T": "Syndicate", + "4-JWWQ": "Syndicate", + "G-6SXJ": "Syndicate", + "S-U8A4": "Syndicate", + "ZV-72W": "Syndicate", + "2G38-I": "Syndicate", + "CY-ZLP": "Syndicate", + "U4-Q2V": "Syndicate", + "98Q-8O": "Syndicate", + "Bei": "Metropolis", + "Uttindar": "Metropolis", + "Hagilur": "Metropolis", + "Anher": "Metropolis", + "Ragnarg": "Metropolis", + "Hek": "Metropolis", + "Hror": "Metropolis", + "Amo": "Metropolis", + "Resbroko": "Metropolis", + "Hadozeko": "Metropolis", + "Ardar": "Metropolis", + "Auner": "Metropolis", + "Evati": "Metropolis", + "Ofstold": "Metropolis", + "Todifrauan": "Metropolis", + "Helgatild": "Metropolis", + "Arnstur": "Metropolis", + "Lasleinur": "Metropolis", + "Arnher": "Metropolis", + "Brin": "Metropolis", + "Nakugard": "Metropolis", + "Traun": "Metropolis", + "Uriok": "Metropolis", + "Barkrik": "Metropolis", + "Inder": "Metropolis", + "Tvink": "Metropolis", + "Lanngisi": "Metropolis", + "Hjoramold": "Metropolis", + "Dudreda": "Metropolis", + "Hakisalki": "Metropolis", + "Arwa": "Metropolis", + "Krirald": "Metropolis", + "Arifsdald": "Metropolis", + "Ansen": "Metropolis", + "Floseswin": "Metropolis", + "Uisper": "Metropolis", + "Aset": "Metropolis", + "Eytjangard": "Metropolis", + "Turnur": "Metropolis", + "Isbrabata": "Metropolis", + "Vimeini": "Metropolis", + "Avenod": "Metropolis", + "Frerstorn": "Metropolis", + "Ontorn": "Metropolis", + "Sirekur": "Metropolis", + "Gebuladi": "Metropolis", + "Ebolfer": "Metropolis", + "Eszur": "Metropolis", + "Hofjaldgund": "Metropolis", + "Klogori": "Metropolis", + "Orfrold": "Metropolis", + "Egmar": "Metropolis", + "Taff": "Metropolis", + "Ualkin": "Metropolis", + "Gukarla": "Metropolis", + "Arlulf": "Metropolis", + "Brundakur": "Metropolis", + "Stirht": "Metropolis", + "Illuin": "Metropolis", + "Nedegulf": "Metropolis", + "Aldilur": "Metropolis", + "Alf": "Metropolis", + "Eust": "Metropolis", + "Flost": "Metropolis", + "Todrir": "Metropolis", + "Asgeir": "Metropolis", + "Evuldgenzo": "Metropolis", + "Ongund": "Metropolis", + "Jondik": "Metropolis", + "Olbra": "Metropolis", + "Altrinur": "Metropolis", + "Vilur": "Metropolis", + "Reset": "Metropolis", + "Eygfe": "Metropolis", + "Eiluvodi": "Metropolis", + "Freatlidur": "Metropolis", + "Roleinn": "Metropolis", + "Maturat": "Metropolis", + "Bongveber": "Metropolis", + "Anbald": "Metropolis", + "Vorsk": "Metropolis", + "Hjortur": "Metropolis", + "Egbonbet": "Metropolis", + "Totkubad": "Metropolis", + "Meimungen": "Metropolis", + "Agtver": "Metropolis", + "Datulen": "Metropolis", + "Situner": "Metropolis", + "Tamekamur": "Metropolis", + "Evettullur": "Metropolis", + "Leurtmar": "Metropolis", + "Ryddinjorn": "Metropolis", + "Arlek": "Metropolis", + "Elgoi": "Metropolis", + "Eram": "Metropolis", + "Yrmori": "Metropolis", + "Aldagolf": "Metropolis", + "Aldrat": "Metropolis", + "Urnhard": "Metropolis", + "Hardbako": "Metropolis", + "Erstur": "Metropolis", + "Fredagod": "Metropolis", + "Libold": "Metropolis", + "Wirdalen": "Metropolis", + "Nein": "Metropolis", + "Enden": "Metropolis", + "Erstet": "Metropolis", + "Anstard": "Metropolis", + "Osvestmunnur": "Metropolis", + "Hilfhurmur": "Metropolis", + "Geffur": "Metropolis", + "Oppold": "Metropolis", + "Tratokard": "Metropolis", + "Lumegen": "Metropolis", + "Gedugaud": "Metropolis", + "Polstodur": "Metropolis", + "Hebisa": "Metropolis", + "Tollus": "Metropolis", + "Ogoten": "Metropolis", + "Earled": "Metropolis", + "Aderkan": "Metropolis", + "Ansher": "Metropolis", + "Earwik": "Metropolis", + "Finanar": "Metropolis", + "Moselgi": "Metropolis", + "Mateber": "Metropolis", + "Iluin": "Metropolis", + "Ofage": "Metropolis", + "Josekorn": "Metropolis", + "Nifflung": "Metropolis", + "Hakeri": "Metropolis", + "Oraekja": "Metropolis", + "Dantbeinn": "Metropolis", + "Irgrus": "Metropolis", + "Orduin": "Metropolis", + "Engosi": "Metropolis", + "Atonder": "Metropolis", + "Hotrardik": "Metropolis", + "Ridoner": "Metropolis", + "Klaevik": "Metropolis", + "Lirerim": "Metropolis", + "Offikatlin": "Metropolis", + "Diromitur": "Metropolis", + "Eldjaerin": "Metropolis", + "Erlendur": "Metropolis", + "Aldik": "Metropolis", + "Tabbetzur": "Metropolis", + "Eurgrana": "Metropolis", + "Frulegur": "Metropolis", + "Hroduko": "Metropolis", + "Hodrold": "Metropolis", + "Odebeinn": "Metropolis", + "Konora": "Metropolis", + "Erindur": "Metropolis", + "Abrat": "Metropolis", + "Orgron": "Metropolis", + "Embod": "Metropolis", + "Erego": "Metropolis", + "Fildar": "Metropolis", + "Amarr": "Domain", + "Boranai": "Domain", + "Hedion": "Domain", + "Mabnen": "Domain", + "Toshabia": "Domain", + "Irnin": "Domain", + "Kehour": "Domain", + "Martha": "Domain", + "Simbeloud": "Domain", + "Ebidan": "Domain", + "Akhragan": "Domain", + "Mikhir": "Domain", + "Bashakru": "Domain", + "Sukirah": "Domain", + "Shuria": "Domain", + "Narai": "Domain", + "Ziona": "Domain", + "Gaha": "Domain", + "Armala": "Domain", + "Murema": "Domain", + "Cailanar": "Domain", + "Ilonarav": "Domain", + "Uchat": "Domain", + "Joppaya": "Domain", + "Pelkia": "Domain", + "Raren": "Domain", + "Mazitah": "Domain", + "Hiramu": "Domain", + "Sakhti": "Domain", + "Aldali": "Domain", + "Hutian": "Domain", + "Noli": "Domain", + "Nomash": "Domain", + "Aghesi": "Domain", + "Fabin": "Domain", + "Airshaz": "Domain", + "Patzcha": "Domain", + "Charra": "Domain", + "Harva": "Domain", + "Thebeka": "Domain", + "Rasile": "Domain", + "Nererut": "Domain", + "Sitanan": "Domain", + "Vashkah": "Domain", + "Ardishapur Prime": "Domain", + "Gid": "Domain", + "Dakba": "Domain", + "Nifshed": "Domain", + "Shumam": "Domain", + "Milal": "Domain", + "Sobenah": "Domain", + "Bourar": "Domain", + "Rammi": "Domain", + "Arodan": "Domain", + "Rimbah": "Domain", + "Mamenkhanar": "Domain", + "Seiradih": "Domain", + "Arera": "Domain", + "Hizhara": "Domain", + "Neziel": "Domain", + "Ahala": "Domain", + "Knophtikoo": "Domain", + "Ruchy": "Domain", + "Hai": "Domain", + "Sadye": "Domain", + "Bika": "Domain", + "Arshat": "Domain", + "Jerma": "Domain", + "Miyeli": "Domain", + "Reyi": "Domain", + "Moussou": "Domain", + "Nadohman": "Domain", + "Sahdil": "Domain", + "Esteban": "Domain", + "Luromooh": "Domain", + "Nalu": "Domain", + "Jarshitsan": "Domain", + "Hadonoo": "Domain", + "Azizora": "Domain", + "Ahmak": "Domain", + "Shabura": "Domain", + "Adia": "Domain", + "Ebo": "Domain", + "Avair": "Domain", + "Rayl": "Domain", + "Asoutar": "Domain", + "Porsharrah": "Domain", + "Tastela": "Domain", + "Clarelam": "Domain", + "Isamm": "Domain", + "Ebtesham": "Domain", + "Artoun": "Domain", + "Safizon": "Domain", + "Zatsyaki": "Domain", + "Eba": "Domain", + "Bhizheba": "Domain", + "Fahruni": "Domain", + "Sahda": "Domain", + "Naguton": "Domain", + "Ealur": "Domain", + "Shajarleg": "Domain", + "Basan": "Domain", + "Akila": "Domain", + "Amod": "Domain", + "Unefsih": "Domain", + "Mista": "Domain", + "Valmu": "Domain", + "Sibot": "Domain", + "Andabiar": "Domain", + "Kheram": "Domain", + "Arbaz": "Domain", + "Penirgman": "Domain", + "Chaven": "Domain", + "Khopa": "Domain", + "Ashab": "Domain", + "Orkashu": "Domain", + "Youl": "Domain", + "Ekid": "Domain", + "Raravoss": "Domain", + "Nakri": "Domain", + "Zaimeth": "Domain", + "Sharhelund": "Domain", + "Mai": "Domain", + "Sharji": "Domain", + "Kudi": "Domain", + "Bahromab": "Domain", + "Madirmilire": "Domain", + "Niarja": "Domain", + "Fabum": "Domain", + "Saana": "Domain", + "Teshi": "Domain", + "Sayartchen": "Domain", + "Gosalav": "Domain", + "Sorzielang": "Domain", + "Somouh": "Domain", + "Abaim": "Domain", + "Ides": "Domain", + "Yeeramoun": "Domain", + "Anila": "Domain", + "Pedel": "Domain", + "Etav": "Domain", + "Saheri": "Domain", + "Lahnina": "Domain", + "Mahrokht": "Domain", + "Alkabsi": "Domain", + "Sarum Prime": "Domain", + "Hama": "Domain", + "Irnal": "Domain", + "Bagodan": "Domain", + "Murzi": "Domain", + "Chesoh": "Domain", + "Herila": "Domain", + "Chemilip": "Domain", + "Raravath": "Domain", + "Hisoufad": "Domain", + "Jesoyeh": "Domain", + "Hahda": "Domain", + "Namaili": "Domain", + "Afivad": "Domain", + "Uzigh": "Domain", + "Erzoh": "Domain", + "Merz": "Domain", + "Miakie": "Domain", + "Sirkahri": "Domain", + "Faswiba": "Domain", + "Hayumtom": "Domain", + "Zanka": "Domain", + "Galeh": "Domain", + "Yuhelia": "Domain", + "Maiah": "Domain", + "Hamse": "Domain", + "Barira": "Domain", + "Lashkai": "Domain", + "Zhilshinou": "Domain", + "Jaswelu": "Domain", + "Ana": "Domain", + "Warouh": "Domain", + "Jambu": "Domain", + "Bittanshal": "Domain", + "Arton": "Domain", + "Sieh": "Domain", + "Madimal": "Domain", + "Mamet": "Domain", + "Hoshoun": "Domain", + "Biphi": "Domain", + "Ziriert": "Domain", + "Misaba": "Domain", + "Rephirib": "Domain", + "Deepari": "Domain", + "Fora": "Domain", + "Hanan": "Domain", + "Horir": "Domain", + "Conomette": "Solitude", + "Aimoguier": "Solitude", + "Yveve": "Solitude", + "Meunvon": "Solitude", + "Cadelanne": "Solitude", + "Elore": "Solitude", + "Anckee": "Solitude", + "Vevelonel": "Solitude", + "Pertnineere": "Solitude", + "Boystin": "Solitude", + "Lour": "Solitude", + "Maire": "Solitude", + "Oerse": "Solitude", + "Octanneve": "Solitude", + "Larryn": "Solitude", + "Niballe": "Solitude", + "Postouvin": "Solitude", + "Odinesyn": "Solitude", + "Weraroix": "Solitude", + "Sarline": "Solitude", + "Aeter": "Solitude", + "Gererique": "Solitude", + "Harner": "Solitude", + "Yvaeroure": "Solitude", + "Vecodie": "Solitude", + "Arasare": "Solitude", + "Yvelet": "Solitude", + "Lazer": "Solitude", + "Stoure": "Solitude", + "Heluene": "Solitude", + "Arittant": "Solitude", + "Oruse": "Solitude", + "Hare": "Solitude", + "Ogaria": "Solitude", + "Faurulle": "Solitude", + "Agaullores": "Solitude", + "Babirmoult": "Solitude", + "Ratillose": "Solitude", + "Ondree": "Solitude", + "Pochelympe": "Solitude", + "Eggheron": "Solitude", + "Toustain": "Solitude", + "Straloin": "Solitude", + "H1-ESN": "Tenal", + "3DR-CR": "Tenal", + "RLTG-3": "Tenal", + "S-EVIQ": "Tenal", + "EOY-BG": "Tenal", + "PNS7-J": "Tenal", + "IG-ZAM": "Tenal", + "0-UVHJ": "Tenal", + "NCG-PW": "Tenal", + "1QH-0K": "Tenal", + "ZH3-BS": "Tenal", + "ZJ-QOO": "Tenal", + "ZXA-V6": "Tenal", + "I1-BE8": "Tenal", + "W8O-19": "Tenal", + "U1TX-A": "Tenal", + "1BWK-S": "Tenal", + "KMV-CQ": "Tenal", + "RKE-CP": "Tenal", + "NV-3KA": "Tenal", + "S-1LIO": "Tenal", + "S-KSWL": "Tenal", + "5-O8B1": "Tenal", + "R-YWID": "Tenal", + "30-D5G": "Tenal", + "HB-FSO": "Tenal", + "J1-KJP": "Tenal", + "KW-1MV": "Tenal", + "G06-8Y": "Tenal", + "U-O2DA": "Tenal", + "WV-0R2": "Tenal", + "SZ6-TA": "Tenal", + "6-AOLS": "Tenal", + "IKTD-P": "Tenal", + "33CE-7": "Tenal", + "L-P3XM": "Tenal", + "DCJ-ZT": "Tenal", + "O36A-P": "Tenal", + "Z-LO6I": "Tenal", + "0M-103": "Tenal", + "6OYQ-Z": "Tenal", + "HE5T-A": "Tenal", + "A-1IJ9": "Tenal", + "Y-YHZQ": "Tenal", + "Z-SR1I": "Tenal", + "GW7P-8": "Tenal", + "SF-XJS": "Tenal", + "A1RR-M": "Tenal", + "AR-5SY": "Tenal", + "OE-4HB": "Tenal", + "ZK-YQ3": "Tenal", + "MZPH-W": "Tenal", + "W0X-MG": "Tenal", + "JI-1UQ": "Tenal", + "EN-GTB": "Tenal", + "U5-XW7": "Tenal", + "JSI-LL": "Tenal", + "M-UC0S": "Tenal", + "V7-MID": "Tenal", + "SY0W-2": "Tenal", + "2-3Q2G": "Tenal", + "Q1U-IU": "Tenal", + "C-XNUA": "Tenal", + "7D-PAT": "Tenal", + "V-LDEJ": "Tenal", + "T-K10W": "Tenal", + "P-UCRP": "Tenal", + "3-QYVE": "Tenal", + "C8-CHY": "Fade", + "E-9ORY": "Fade", + "CR-IFM": "Fade", + "HHK-VL": "Fade", + "P-33KR": "Fade", + "DO6H-Q": "Fade", + "DW-T2I": "Fade", + "O-CNPR": "Fade", + "L-SCBU": "Fade", + "VRH-H7": "Fade", + "O1Y-ED": "Fade", + "K4YZ-Y": "Fade", + "X36Y-G": "Fade", + "L-C3O7": "Fade", + "YKSC-A": "Fade", + "FIO1-8": "Fade", + "C-OK0R": "Fade", + "0-ARFO": "Fade", + "E9KD-N": "Fade", + "8W-OSE": "Fade", + "WQY-IQ": "Fade", + "C4C-Z4": "Fade", + "GME-PQ": "Fade", + "MPPA-A": "Fade", + "X5-UME": "Fade", + "I-UUI5": "Fade", + "8QMO-E": "Fade", + "G-5EN2": "Providence", + "9-F0B2": "Providence", + "YWS0-Z": "Providence", + "4B-NQN": "Providence", + "9UY4-H": "Providence", + "49GC-R": "Providence", + "D-GTMI": "Providence", + "FSW-3C": "Providence", + "FX-7EM": "Providence", + "MH9C-S": "Providence", + "G7AQ-7": "Providence", + "QBL-BV": "Providence", + "T-RPFU": "Providence", + "I7S-1S": "Providence", + "U-HYMT": "Providence", + "FC-3YI": "Providence", + "QR-K85": "Providence", + "5IO8-U": "Providence", + "DP-JD4": "Providence", + "OXIY-V": "Providence", + "H6-CX8": "Providence", + "D61A-G": "Providence", + "Shintaht": "Providence", + "Y-MPWL": "Providence", + "D-6WS1": "Providence", + "SI-I89": "Providence", + "KBP7-G": "Providence", + "B-WPLZ": "Providence", + "XHQ-7V": "Providence", + "E-YCML": "Providence", + "TU-O0T": "Providence", + "Y9-MDG": "Providence", + "PI5-39": "Providence", + "GN7-XY": "Providence", + "F-DTOO": "Providence", + "5KG-PY": "Providence", + "QO-SRI": "Providence", + "INQ-WR": "Providence", + "S9X-AX": "Providence", + "TU-RI6": "Providence", + "08Z-JJ": "Providence", + "X-4WZD": "Providence", + "6-OQJV": "Providence", + "AY-YCU": "Providence", + "ZT-LPU": "Providence", + "3GXF-U": "Providence", + "VKI-T7": "Providence", + "8P9-BM": "Providence", + "F-YH5B": "Providence", + "H-GKI6": "Providence", + "YQB-22": "Providence", + "2-TEGJ": "Providence", + "MVCJ-E": "Providence", + "AY-24I": "Providence", + "BK4-YC": "Providence", + "K1I1-J": "Providence", + "LF-2KP": "Providence", + "JEIV-E": "Providence", + "O-Y5JQ": "Providence", + "DNR-7M": "Providence", + "N-RMSH": "Providence", + "K1Y-5H": "Providence", + "IWZ3-C": "Providence", + "1-1I53": "Providence", + "N8XA-L": "Providence", + "18-GZM": "Providence", + "R3-K7K": "Providence", + "X-R3NM": "Providence", + "8B-VLX": "Providence", + "G-B22J": "Providence", + "X6AB-Y": "Providence", + "2V-CS5": "Providence", + "H9-J8N": "Providence", + "HP-6Z6": "Providence", + "GA9P-0": "Providence", + "7YWV-S": "Providence", + "TXJ-II": "Providence", + "C1-HAB": "Providence", + "3KB-J0": "Providence", + "0B-HLZ": "Providence", + "Z-RFE3": "Providence", + "I-MGAB": "Providence", + "18XA-C": "Providence", + "3D-CQU": "Providence", + "Agoze": "Placid", + "Intaki": "Placid", + "Brarel": "Placid", + "Vey": "Placid", + "Annancale": "Placid", + "Ostingele": "Placid", + "Harroule": "Placid", + "Stacmon": "Placid", + "Covryn": "Placid", + "Iges": "Placid", + "Dastryns": "Placid", + "Slays": "Placid", + "Uphallant": "Placid", + "Alperaute": "Placid", + "Aunsou": "Placid", + "Cumemare": "Placid", + "Reynire": "Placid", + "Pain": "Placid", + "Gare": "Placid", + "Pelille": "Placid", + "Dour": "Placid", + "Grispire": "Placid", + "Brellystier": "Placid", + "Vivanier": "Placid", + "Algasienan": "Placid", + "Osmallanais": "Placid", + "Ivorider": "Placid", + "Mollin": "Placid", + "Iffrue": "Placid", + "Vilinnon": "Placid", + "Ommaerrer": "Placid", + "Aulbres": "Placid", + "Barleguet": "Placid", + "Vestouve": "Placid", + "Ausmaert": "Placid", + "Espigoure": "Placid", + "Kenninck": "Placid", + "Archavoinet": "Placid", + "Eugales": "Placid", + "Frarie": "Placid", + "Aubenall": "Placid", + "Moclinamaud": "Placid", + "Renarelle": "Placid", + "Orvolle": "Placid", + "Osmeden": "Placid", + "Adacyne": "Placid", + "Oulley": "Placid", + "Chardalane": "Placid", + "Maut": "Placid", + "Vlillirier": "Placid", + "Aldranette": "Placid", + "Oicx": "Placid", + "Evaulon": "Placid", + "Anchauttes": "Placid", + "Alsavoinon": "Placid", + "Esesier": "Placid", + "Avaux": "Placid", + "Gallusiene": "Placid", + "Ruerrotta": "Placid", + "Hedoubel": "Placid", + "Amoen": "Placid", + "Amasiree": "Placid", + "Aubonnie": "Placid", + "Alparena": "Placid", + "Reschard": "Placid", + "Arderonne": "Placid", + "Mercomesier": "Placid", + "Alamel": "Placid", + "Mantenault": "Placid", + "Athounon": "Placid", + "Odamia": "Placid", + "Gousoviba": "Khanid", + "Neyi": "Khanid", + "Kihtaled": "Khanid", + "Ipref": "Khanid", + "Agil": "Khanid", + "Khanid Prime": "Khanid", + "Jachanu": "Khanid", + "Sazre": "Khanid", + "Bukah": "Khanid", + "Ervekam": "Khanid", + "Mashtarmem": "Khanid", + "Sehsasez": "Khanid", + "Osis": "Khanid", + "Geztic": "Khanid", + "Yezara": "Khanid", + "Kahah": "Khanid", + "Saloti": "Khanid", + "Hishai": "Khanid", + "Molea": "Khanid", + "Gidali": "Khanid", + "Palas": "Khanid", + "Safshela": "Khanid", + "Reteka": "Khanid", + "Moniyyuku": "Khanid", + "Lansez": "Khanid", + "Keberz": "Khanid", + "Nourbal": "Khanid", + "Arzanni": "Khanid", + "Ashmarir": "Khanid", + "Kaira": "Khanid", + "Badivefi": "Khanid", + "Talidal": "Khanid", + "Ashi": "Khanid", + "Tzashrah": "Khanid", + "Efa": "Khanid", + "Moro": "Khanid", + "Sabusi": "Khanid", + "Ainsan": "Khanid", + "Claini": "Khanid", + "Gehi": "Khanid", + "Seshala": "Khanid", + "Vezila": "Khanid", + "Ham": "Khanid", + "Upt": "Khanid", + "Hemouner": "Khanid", + "Afnakat": "Khanid", + "Col": "Khanid", + "Chamemi": "Khanid", + "Firbha": "Khanid", + "Tegheon": "Khanid", + "Bashyam": "Khanid", + "Parses": "Khanid", + "Balanaz": "Khanid", + "Edani": "Khanid", + "Danera": "Khanid", + "Bomana": "Khanid", + "Rahabeda": "Khanid", + "Aurejet": "Khanid", + "Rilera": "Khanid", + "Amafi": "Khanid", + "Hakana": "Khanid", + "Ashkoo": "Khanid", + "Baratar": "Khanid", + "Arzieh": "Khanid", + "Nahrneder": "Khanid", + "Nandeza": "Khanid", + "Dimoohan": "Khanid", + "Chitiamem": "Khanid", + "Kuhri": "Khanid", + "Zahefeus": "Khanid", + "Zephan": "Khanid", + "Neda": "Khanid", + "Goudiyah": "Khanid", + "Sassecho": "Khanid", + "Timudan": "Khanid", + "Ibani": "Khanid", + "Cabeki": "Khanid", + "Irmalin": "Khanid", + "Nakis": "Khanid", + "Hezere": "Khanid", + "Fanathor": "Khanid", + "Zirsem": "Khanid", + "Pout": "Khanid", + "Rafeme": "Khanid", + "A2-V27": "Querious", + "T8H-66": "Querious", + "A3-LOG": "Querious", + "7V-KHW": "Querious", + "O3L-95": "Querious", + "0-WT2D": "Querious", + "7GCD-P": "Querious", + "G-3BOG": "Querious", + "K7D-II": "Querious", + "L-6BE1": "Querious", + "1M4-FK": "Querious", + "V-LEKM": "Querious", + "9ES-SI": "Querious", + "UQY-IK": "Querious", + "60M-TG": "Querious", + "0TKF-6": "Querious", + "TV8-HS": "Querious", + "VT-G2P": "Querious", + "YOP-0T": "Querious", + "9-HM04": "Querious", + "MKD-O8": "Querious", + "GOP-GE": "Querious", + "SKR-SP": "Querious", + "V-3U8T": "Querious", + "T8T-RA": "Querious", + "A-BO4V": "Querious", + "W-IX39": "Querious", + "K-B8DK": "Querious", + "L-6W1J": "Querious", + "P4-3TJ": "Querious", + "K-Z0V4": "Querious", + "LNVW-K": "Querious", + "8B-SAJ": "Querious", + "Q2-N6W": "Querious", + "C-9RRR": "Querious", + "A-5F4A": "Querious", + "P-ZMZV": "Querious", + "9CG6-H": "Querious", + "NDII-Q": "Querious", + "UYU-VV": "Querious", + "K-L690": "Querious", + "W6V-VM": "Querious", + "OGY-6D": "Querious", + "8-SNUD": "Querious", + "H-4R6Z": "Querious", + "IGE-NE": "Querious", + "UVHO-F": "Querious", + "Z-XX2J": "Querious", + "YW-SYT": "Querious", + "Z-UZZN": "Querious", + "DS-LO3": "Querious", + "BX2-ZX": "Querious", + "RF-CN3": "Querious", + "C-7SBM": "Querious", + "ZAU-JW": "Querious", + "YF-6L1": "Querious", + "K-YI1L": "Querious", + "KEJY-U": "Querious", + "3BK-O7": "Querious", + "8-GE2P": "Querious", + "QXQ-I6": "Querious", + "L3-I3K": "Querious", + "3-JCJT": "Querious", + "W-IIYI": "Querious", + "AO-N1P": "Querious", + "4-GJT1": "Querious", + "5V-BJI": "Querious", + "49-U6U": "Querious", + "M1BZ-2": "Querious", + "N-M1A3": "Querious", + "8QT-H4": "Querious", + "F2OY-X": "Querious", + "4-2UXV": "Querious", + "RKM-GE": "Querious", + "DG-L7S": "Querious", + "K4-RFZ": "Querious", + "L-FVHR": "Querious", + "3-FKCZ": "Querious", + "ED-L9T": "Querious", + "LS-V29": "Querious", + "9SBB-9": "Querious", + "I1Y-IU": "Querious", + "U-HYZN": "Querious", + "8-YNBE": "Querious", + "YQX-7U": "Querious", + "QY1E-N": "Querious", + "E-VKJV": "Querious", + "BX-VEX": "Querious", + "B-7DFU": "Querious", + "ZXJ-71": "Querious", + "F-NXLQ": "Querious", + "ES-Q0W": "Querious", + "H74-B0": "Querious", + "NU4-2G": "Querious", + "3D5K-R": "Querious", + "1-3HWZ": "Cloud Ring", + "XT-R36": "Cloud Ring", + "5-MLDT": "Cloud Ring", + "B-DBYQ": "Cloud Ring", + "QXW-PV": "Cloud Ring", + "DY-F70": "Cloud Ring", + "FD53-H": "Cloud Ring", + "O-ZXUV": "Cloud Ring", + "77-KDQ": "Cloud Ring", + "F7C-H0": "Cloud Ring", + "TN-T7T": "Cloud Ring", + "1-NW2G": "Cloud Ring", + "O-IVNH": "Cloud Ring", + "O-0HW8": "Cloud Ring", + "YI-8ZM": "Cloud Ring", + "OU-X3P": "Cloud Ring", + "6-4V20": "Cloud Ring", + "Q-UA3C": "Cloud Ring", + "W-4NUU": "Cloud Ring", + "8R-RTB": "Cloud Ring", + "6Z9-0M": "Cloud Ring", + "FQ9W-C": "Cloud Ring", + "9-4RP2": "Cloud Ring", + "O-BDXB": "Cloud Ring", + "G8AD-C": "Cloud Ring", + "XZH-4X": "Cloud Ring", + "Z-Y7R7": "Cloud Ring", + "MJYW-3": "Cloud Ring", + "PPG-XC": "Cloud Ring", + "QA1-BT": "Cloud Ring", + "5S-KNL": "Cloud Ring", + "00TY-J": "Cloud Ring", + "XG-D1L": "Cloud Ring", + "6RCQ-V": "Cloud Ring", + "28O-JY": "Cloud Ring", + "CX7-70": "Cloud Ring", + "6ON-RW": "Cloud Ring", + "U65-CN": "Cloud Ring", + "X-M9ON": "Cloud Ring", + "P5-KCC": "Cloud Ring", + "Hiroudeh": "Kador", + "Dresi": "Kador", + "Aphend": "Kador", + "Romi": "Kador", + "Zororzih": "Kador", + "Aharalel": "Kador", + "Gensela": "Kador", + "Ghesis": "Kador", + "Gamdis": "Kador", + "Joamma": "Kador", + "Gonan": "Kador", + "Joramok": "Kador", + "Neburab": "Kador", + "Aband": "Kador", + "Uanim": "Kador", + "Murini": "Kador", + "Askonak": "Kador", + "Nordar": "Kador", + "Kador Prime": "Kador", + "Khafis": "Kador", + "Dantan": "Kador", + "Turba": "Kador", + "Sonama": "Kador", + "Halibai": "Kador", + "Suner": "Kador", + "Inis-Ilix": "Kador", + "Kothe": "Kador", + "Ansasos": "Kador", + "Dehrokh": "Kador", + "Bordan": "Kador", + "Zimmem": "Kador", + "Chaneya": "Kador", + "Oberen": "Kador", + "Finid": "Kador", + "Yarebap": "Kador", + "Mandoo": "Kador", + "Miah": "Kador", + "Peyiri": "Kador", + "Kamda": "Kador", + "Rayeret": "Kador", + "Bushemal": "Kador", + "Ardhis": "Kador", + "Gasavak": "Kador", + "Iaokit": "Kador", + "Menri": "Kador", + "Chanoun": "Kador", + "Garisas": "Kador", + "Aphi": "Kador", + "Jakri": "Kador", + "Nidupad": "Kador", + "Zimse": "Kador", + "Koona": "Kador", + "Munory": "Kador", + "Hostakoh": "Kador", + "Yooh": "Kador", + "Jeshideh": "Kador", + "Hilmar": "Kador", + "Kasi": "Kador", + "Shura": "Kador", + "Mod": "Kador", + "Omam": "Kador", + "Bersyrim": "Kador", + "Sechmaren": "Kador", + "Zinoo": "Kador", + "Hiremir": "Kador", + "Hikansog": "Kador", + "Syrikos": "Kador", + "Yebouz": "Kador", + "Hapala": "Kador", + "Salah": "Kador", + "Akhmoh": "Kador", + "Jennim": "Kador", + "Elmed": "Kador", + "Shaggoth": "Kador", + "Ustnia": "Kador", + "Kooreng": "Kador", + "Minin": "Kador", + "Yehnifi": "Kador", + "Shemah": "Kador", + "Asrios": "Kador", + "Ithar": "Kador", + "Telang": "Kador", + "Lazara": "Kador", + "Zorrabed": "Kador", + "Akhwa": "Kador", + "FV-YEA": "Cobalt Edge", + "J-A5QD": "Cobalt Edge", + "BI0Y-X": "Cobalt Edge", + "SK7-G6": "Cobalt Edge", + "4-PCHD": "Cobalt Edge", + "5-3722": "Cobalt Edge", + "GQLB-V": "Cobalt Edge", + "5E-EZC": "Cobalt Edge", + "9KE-IT": "Cobalt Edge", + "P-NRD3": "Cobalt Edge", + "Y-RAW3": "Cobalt Edge", + "S-W8CF": "Cobalt Edge", + "X-41DA": "Cobalt Edge", + "YVSL-2": "Cobalt Edge", + "5E6I-W": "Cobalt Edge", + "KIG9-K": "Cobalt Edge", + "I-CMZA": "Cobalt Edge", + "H23-B5": "Cobalt Edge", + "A-0IIQ": "Cobalt Edge", + "CBY8-J": "Cobalt Edge", + "E-BYOS": "Cobalt Edge", + "ETXT-F": "Cobalt Edge", + "MK-YNM": "Cobalt Edge", + "2-9Z6V": "Cobalt Edge", + "5HN-D6": "Cobalt Edge", + "E-B957": "Cobalt Edge", + "P-H5IY": "Cobalt Edge", + "4A-6NI": "Cobalt Edge", + "1M7-RK": "Cobalt Edge", + "87-1PM": "Cobalt Edge", + "C2-1B5": "Cobalt Edge", + "JE-VLG": "Cobalt Edge", + "5ED-4E": "Cobalt Edge", + "B-U299": "Cobalt Edge", + "DN58-U": "Cobalt Edge", + "VAF1-P": "Cobalt Edge", + "FV1-RQ": "Cobalt Edge", + "QT-EBC": "Cobalt Edge", + "O-F4SN": "Cobalt Edge", + "CUT-0V": "Cobalt Edge", + "9-WEMC": "Cobalt Edge", + "U6R-F9": "Cobalt Edge", + "L-Z9NB": "Cobalt Edge", + "EJ-5X2": "Cobalt Edge", + "HXK-J6": "Cobalt Edge", + "4LNE-M": "Cobalt Edge", + "DK0-N8": "Cobalt Edge", + "E0DR-G": "Cobalt Edge", + "KI2-S3": "Cobalt Edge", + "CHP-76": "Cobalt Edge", + "T-67F8": "Cobalt Edge", + "58Z-IH": "Cobalt Edge", + "M-VACR": "Cobalt Edge", + "0B-VOJ": "Cobalt Edge", + "J-QOKQ": "Cobalt Edge", + "4GSZ-1": "Cobalt Edge", + "E-EFAM": "Cobalt Edge", + "SBEN-Q": "Cobalt Edge", + "9-7SRQ": "Cobalt Edge", + "VEQ-3V": "Cobalt Edge", + "4T-VDE": "Cobalt Edge", + "D9Z-VY": "Cobalt Edge", + "MO-YDG": "Cobalt Edge", + "42SU-L": "Cobalt Edge", + "RGU1-T": "Cobalt Edge", + "1GT-MA": "Cobalt Edge", + "VY-866": "Cobalt Edge", + "HB-5L3": "Cobalt Edge", + "Q-VTWJ": "Cobalt Edge", + "Van": "Aridia", + "Shakasi": "Aridia", + "Zayi": "Aridia", + "Shirshocin": "Aridia", + "Maalna": "Aridia", + "Maseera": "Aridia", + "Yehaba": "Aridia", + "Kenahehab": "Aridia", + "Gens": "Aridia", + "Kamih": "Aridia", + "Hier": "Aridia", + "Jasson": "Aridia", + "Sadana": "Aridia", + "Isid": "Aridia", + "Onanam": "Aridia", + "Udianoor": "Aridia", + "Vehan": "Aridia", + "Marmeha": "Aridia", + "Haimeh": "Aridia", + "Avada": "Aridia", + "Chibi": "Aridia", + "Mishi": "Aridia", + "Bazadod": "Aridia", + "Pahineh": "Aridia", + "Fihrneh": "Aridia", + "Parouz": "Aridia", + "Edilkam": "Aridia", + "Hakatiz": "Aridia", + "Khnar": "Aridia", + "Ertoo": "Aridia", + "Yiratal": "Aridia", + "Balas": "Aridia", + "Pemsah": "Aridia", + "Feshur": "Aridia", + "Hoseen": "Aridia", + "Yekh": "Aridia", + "Gesh": "Aridia", + "Nema": "Aridia", + "Shenda": "Aridia", + "Rashagh": "Aridia", + "Sazilid": "Aridia", + "Afrah": "Aridia", + "Sota": "Aridia", + "Soliara": "Aridia", + "Nielez": "Aridia", + "Tukanas": "Aridia", + "Fageras": "Aridia", + "Ajna": "Aridia", + "Sheri": "Aridia", + "Ahraghen": "Aridia", + "Nalnifan": "Aridia", + "Jerhesh": "Aridia", + "Getrenjesa": "Aridia", + "Shafrak": "Aridia", + "Defsunun": "Aridia", + "Zazamye": "Aridia", + "Yahyerer": "Aridia", + "Esubara": "Aridia", + "Ghekon": "Aridia", + "Vaini": "Aridia", + "Zaveral": "Aridia", + "Anohel": "Aridia", + "Soza": "Aridia", + "Pserz": "Aridia", + "Illi": "Aridia", + "Keba": "Aridia", + "Bapraya": "Aridia", + "Efu": "Aridia", + "Tisot": "Aridia", + "Sakht": "Aridia", + "Naga": "Aridia", + "Anath": "Aridia", + "Omigiav": "Aridia", + "Fobiner": "Aridia", + "Huna": "Aridia", + "Esaeel": "Aridia", + "Karan": "Aridia", + "Nouta": "Aridia", + "Ned": "Aridia", + "Hophib": "Aridia", + "UQ9-3C": "Branch", + "DCI7-7": "Branch", + "J7YR-1": "Branch", + "PKG4-7": "Branch", + "EWN-2U": "Branch", + "VL3I-M": "Branch", + "KMC-WI": "Branch", + "4-48K1": "Branch", + "NTV0-1": "Branch", + "C-HCGU": "Branch", + "XW-2XP": "Branch", + "Q-FEEJ": "Branch", + "0P9Z-I": "Branch", + "AH-B84": "Branch", + "JTAU-5": "Branch", + "HB7R-F": "Branch", + "O-JPKH": "Branch", + "F-9F6Q": "Branch", + "B-GC1T": "Branch", + "V8W-QS": "Branch", + "JRZ-B9": "Branch", + "X4UV-Z": "Branch", + "S-B7IT": "Branch", + "BKG-Q2": "Branch", + "OJ-A8M": "Branch", + "CX-1XF": "Branch", + "3-TD6L": "Branch", + "Q-NJZ4": "Branch", + "NLPB-0": "Branch", + "R4O-I6": "Branch", + "KL3O-J": "Branch", + "Z-K495": "Branch", + "XM-4L0": "Branch", + "QCWA-Z": "Branch", + "52G-NZ": "Branch", + "5LJ-MD": "Branch", + "B8O-KJ": "Branch", + "6-O5GY": "Branch", + "KV-8SN": "Branch", + "UB-UQZ": "Branch", + "YG-82V": "Branch", + "8-4GQM": "Branch", + "T-Q2DD": "Branch", + "LRWD-B": "Branch", + "QXQ-BA": "Branch", + "X7R-JW": "Branch", + "M-HU4V": "Branch", + "CS-ZGD": "Branch", + "3-N3OO": "Branch", + "A-G1FM": "Branch", + "4-BE0M": "Branch", + "I-7RIS": "Branch", + "P7Z-R3": "Branch", + "ZIU-EP": "Branch", + "LXWN-W": "Branch", + "C-LP3N": "Branch", + "9F-7PZ": "Branch", + "1G-MJE": "Branch", + "WO-AIJ": "Branch", + "MA-VDX": "Branch", + "RO90-H": "Branch", + "BWI1-9": "Branch", + "C-LBQS": "Branch", + "J52-BH": "Branch", + "5-P1Y2": "Branch", + "KMQ4-V": "Branch", + "KJ-QWL": "Branch", + "SVB-RE": "Branch", + "C-4ZOS": "Branch", + "K-8SQS": "Branch", + "C-VGYO": "Branch", + "O94U-A": "Branch", + "XW-JHT": "Branch", + "NEH-CS": "Branch", + "4DTQ-K": "Branch", + "J9-5MQ": "Branch", + "D4R-H7": "Branch", + "313I-B": "Branch", + "EQI2-2": "Branch", + "Q-4DEC": "Branch", + "3F-JZF": "Branch", + "5-0WB9": "Branch", + "W-4FA9": "Branch", + "1IX-C0": "Branch", + "2B7A-3": "Branch", + "PUWL-4": "Branch", + "Y-1918": "Branch", + "9-B1DS": "Branch", + "ME-4IU": "Branch", + "BU-IU4": "Branch", + "I-7JR4": "Branch", + "CH9L-K": "Branch", + "QYZM-W": "Branch", + "3KNA-N": "Branch", + "UD-VZW": "Feythabolis", + "3-YX2D": "Feythabolis", + "V-TN6Q": "Feythabolis", + "CFLF-P": "Feythabolis", + "QBH5-F": "Feythabolis", + "9-ZFCG": "Feythabolis", + "J-TPTA": "Feythabolis", + "PMV-G6": "Feythabolis", + "5-IZGE": "Feythabolis", + "OXC-UL": "Feythabolis", + "F-8Y13": "Feythabolis", + "4AZ-J8": "Feythabolis", + "X6-J6R": "Feythabolis", + "BGN1-O": "Feythabolis", + "DUU1-K": "Feythabolis", + "3L-Y9M": "Feythabolis", + "BLC-X0": "Feythabolis", + "K-X5AX": "Feythabolis", + "BJD4-E": "Feythabolis", + "TSG-NO": "Feythabolis", + "O9V-R7": "Feythabolis", + "Z-PNIA": "Feythabolis", + "OCU4-R": "Feythabolis", + "BG-W90": "Feythabolis", + "Y-YGMW": "Feythabolis", + "75C-WN": "Feythabolis", + "I5Q2-S": "Feythabolis", + "PO-3QW": "Feythabolis", + "5XR-KZ": "Feythabolis", + "VF-FN6": "Feythabolis", + "C-0ND2": "Feythabolis", + "JI-LGM": "Feythabolis", + "U-BXU9": "Feythabolis", + "ZXOG-O": "Feythabolis", + "NW2S-A": "Feythabolis", + "U-JJEW": "Feythabolis", + "NX5W-U": "Feythabolis", + "U1-C18": "Feythabolis", + "6O-XIO": "Feythabolis", + "H65-HE": "Feythabolis", + "BJ-ZFD": "Feythabolis", + "5ELE-A": "Feythabolis", + "H-P4LB": "Feythabolis", + "2UK4-N": "Feythabolis", + "QK-CDG": "Feythabolis", + "M-CMLV": "Feythabolis", + "AZN-D2": "Feythabolis", + "E-PR0S": "Feythabolis", + "TR07-S": "Feythabolis", + "VNGJ-U": "Feythabolis", + "2-F3OE": "Feythabolis", + "5-LCI7": "Feythabolis", + "Y2-I3W": "Feythabolis", + "VVO-R6": "Feythabolis", + "CL-J9W": "Feythabolis", + "YHP2-D": "Feythabolis", + "J94-MU": "Feythabolis", + "M2GJ-X": "Feythabolis", + "JO-32L": "Feythabolis", + "UB5Z-3": "Feythabolis", + "MSKR-1": "Feythabolis", + "GPUS-A": "Feythabolis", + "3-BADZ": "Feythabolis", + "23M-PX": "Feythabolis", + "UTDH-N": "Feythabolis", + "ZS-2LT": "Feythabolis", + "DB1R-4": "Feythabolis", + "P8-BKO": "Feythabolis", + "RIT-A7": "Feythabolis", + "R4K-8L": "Feythabolis", + "GHZ-SJ": "Feythabolis", + "K-J50B": "Feythabolis", + "NLO-3Z": "Feythabolis", + "5P-AIP": "Feythabolis", + "M-PGT0": "Feythabolis", + "NPD9-A": "Feythabolis", + "D6SK-L": "Feythabolis", + "HYPL-V": "Feythabolis", + "I9-ZQZ": "Feythabolis", + "0OYZ-G": "Feythabolis", + "SWBV-2": "Feythabolis", + "R97-CI": "Feythabolis", + "6-ELQP": "Feythabolis", + "OBK-K8": "Feythabolis", + "KJ-V0P": "Feythabolis", + "ZID-LE": "Feythabolis", + "K-9UG4": "Feythabolis", + "D4-2XN": "Feythabolis", + "2-RSC7": "Feythabolis", + "C0T-77": "Outer Ring", + "RL-KT0": "Outer Ring", + "UO9-YG": "Outer Ring", + "ZQP-QV": "Outer Ring", + "P-NUWP": "Outer Ring", + "ZJQH-S": "Outer Ring", + "E9G-MT": "Outer Ring", + "TQ-RR8": "Outer Ring", + "1L-BHT": "Outer Ring", + "D5IW-F": "Outer Ring", + "F-XWIN": "Outer Ring", + "4C-B7X": "Outer Ring", + "LGUZ-1": "Outer Ring", + "BF-SDP": "Outer Ring", + "F5FO-U": "Outer Ring", + "5WAE-M": "Outer Ring", + "0-WVQS": "Outer Ring", + "0-9UHT": "Outer Ring", + "M-NKZM": "Outer Ring", + "H-M1BY": "Outer Ring", + "J1H-R4": "Outer Ring", + "J9SH-A": "Outer Ring", + "JKJ-VJ": "Outer Ring", + "RTX0-S": "Outer Ring", + "33FN-P": "Outer Ring", + "NM-OEA": "Outer Ring", + "MT-2VJ": "Outer Ring", + "3HQC-6": "Outer Ring", + "OX-RGN": "Outer Ring", + "R-OCBA": "Outer Ring", + "GA-2V7": "Outer Ring", + "DB-6W4": "Outer Ring", + "7-692B": "Outer Ring", + "L3-XYO": "Outer Ring", + "AN-G54": "Outer Ring", + "ZXI-K2": "Outer Ring", + "T-Z6J2": "Outer Ring", + "CT7-5V": "Outer Ring", + "2JJ-0E": "Outer Ring", + "B0C-LD": "Outer Ring", + "NP6-38": "Outer Ring", + "G-YT55": "Outer Ring", + "IZ-AOB": "Outer Ring", + "G5-EN3": "Outer Ring", + "W-Z3HW": "Outer Ring", + "W2F-ZH": "Outer Ring", + "BMU-V1": "Outer Ring", + "ZXC8-1": "Outer Ring", + "LBV-Q1": "Outer Ring", + "Z-40CG": "Outer Ring", + "O-RIDF": "Outer Ring", + "A-5M31": "Outer Ring", + "BOE7-P": "Outer Ring", + "E-GCX0": "Outer Ring", + "VBFC-8": "Outer Ring", + "YVA-F0": "Outer Ring", + "0D-CHA": "Outer Ring", + "A2V6-6": "Outer Ring", + "VJ0-81": "Outer Ring", + "XF-TQL": "Fountain", + "4-EP12": "Fountain", + "YZS5-4": "Fountain", + "3WE-KY": "Fountain", + "IR-WT1": "Fountain", + "9-VO0Q": "Fountain", + "A8-XBW": "Fountain", + "PNQY-Y": "Fountain", + "RP2-OQ": "Fountain", + "YVBE-E": "Fountain", + "BYXF-Q": "Fountain", + "AC2E-3": "Fountain", + "C-C99Z": "Fountain", + "CL-BWB": "Fountain", + "R3W-XU": "Fountain", + "E-BWUU": "Fountain", + "Y-1W01": "Fountain", + "9R4-EJ": "Fountain", + "SPLE-Y": "Fountain", + "Q-XEB3": "Fountain", + "K8L-X7": "Fountain", + "5-D82P": "Fountain", + "8ESL-G": "Fountain", + "JGOW-Y": "Fountain", + "APM-6K": "Fountain", + "RE-C26": "Fountain", + "AL8-V4": "Fountain", + "KCT-0A": "Fountain", + "N2-OQG": "Fountain", + "OW-TPO": "Fountain", + "9O-ORX": "Fountain", + "IGE-RI": "Fountain", + "Z9PP-H": "Fountain", + "7-8S5X": "Fountain", + "EI-O0O": "Fountain", + "7X-02R": "Fountain", + "D2AH-Z": "Fountain", + "J5A-IX": "Fountain", + "B17O-R": "Fountain", + "6F-H3W": "Fountain", + "H-NPXW": "Fountain", + "L-1SW8": "Fountain", + "U-SOH2": "Fountain", + "DBRN-Z": "Fountain", + "00GD-D": "Fountain", + "C1XD-X": "Fountain", + "G95F-H": "Fountain", + "B32-14": "Fountain", + "C-N4OD": "Fountain", + "CHA2-Q": "Fountain", + "UAYL-F": "Fountain", + "ESC-RI": "Fountain", + "671-ST": "Fountain", + "A-HZYL": "Fountain", + "H-S80W": "Fountain", + "Z30S-A": "Fountain", + "6VDT-H": "Fountain", + "NDH-NV": "Fountain", + "QV28-G": "Fountain", + "15U-JY": "Fountain", + "NY6-FH": "Fountain", + "XJP-Y7": "Fountain", + "AV-VB6": "Fountain", + "HMF-9D": "Fountain", + "7BX-6F": "Fountain", + "YZ-LQL": "Fountain", + "MN5N-X": "Fountain", + "A-1CON": "Fountain", + "75FA-Z": "Fountain", + "WY-9LL": "Fountain", + "D-Q04X": "Fountain", + "Serpentis Prime": "Fountain", + "P5-EFH": "Fountain", + "L-A5XP": "Fountain", + "D4KU-5": "Fountain", + "YRNJ-8": "Fountain", + "3ZTV-V": "Fountain", + "9D6O-M": "Fountain", + "LIWW-P": "Fountain", + "G-UTHL": "Fountain", + "38IA-E": "Fountain", + "M-KXEH": "Fountain", + "TU-Y2A": "Fountain", + "7BIX-A": "Fountain", + "I-CUVX": "Fountain", + "J-RQMF": "Fountain", + "TEG-SD": "Fountain", + "14YI-D": "Fountain", + "87XQ-0": "Fountain", + "LJ-TZW": "Fountain", + "KVN-36": "Fountain", + "57-KJB": "Fountain", + "V6-NY1": "Fountain", + "OL3-78": "Fountain", + "9DQW-W": "Fountain", + "PXF-RF": "Fountain", + "R-BGSU": "Fountain", + "O-PNSN": "Fountain", + "1-5GBW": "Fountain", + "C-FER9": "Fountain", + "F2-2C3": "Fountain", + "F-88PJ": "Fountain", + "ATQ-QS": "Fountain", + "XUW-3X": "Fountain", + "006-L3": "Fountain", + "PB-0C1": "Fountain", + "ZUE-NS": "Fountain", + "L7-APB": "Fountain", + "ZTS-4D": "Fountain", + "4HS-CR": "Fountain", + "WMH-SO": "Fountain", + "LBGI-2": "Fountain", + "G1CA-Y": "Fountain", + "Y-2ANO": "Fountain", + "Z-YN5Y": "Fountain", + "JI-K5H": "Paragon Soul", + "33-JRO": "Paragon Soul", + "ARBX-9": "Paragon Soul", + "5-CSE3": "Paragon Soul", + "O-MCZR": "Paragon Soul", + "9T-APQ": "Paragon Soul", + "4Y-OBL": "Paragon Soul", + "0-MX34": "Paragon Soul", + "5AQ-5H": "Paragon Soul", + "T-ZFID": "Paragon Soul", + "0ZN7-G": "Paragon Soul", + "H8-ZTO": "Paragon Soul", + "YV-FDG": "Paragon Soul", + "LUL-WX": "Paragon Soul", + "8Q-UYU": "Paragon Soul", + "3PPT-9": "Paragon Soul", + "S-KU8B": "Paragon Soul", + "JK-GLL": "Paragon Soul", + "UAAU-C": "Paragon Soul", + "HHJD-5": "Paragon Soul", + "ZWV-GD": "Paragon Soul", + "1DDR-X": "Paragon Soul", + "LG-WA9": "Paragon Soul", + "AA-GWF": "Paragon Soul", + "O4T-Z5": "Paragon Soul", + "O-97ZG": "Paragon Soul", + "2I-520": "Paragon Soul", + "GQ2S-8": "Paragon Soul", + "0SUF-3": "Paragon Soul", + "G-M4GK": "Paragon Soul", + "G1D0-G": "Paragon Soul", + "KU3-BB": "Paragon Soul", + "O1Q-P1": "Paragon Soul", + "LD-2VL": "Paragon Soul", + "ZBY-0I": "Paragon Soul", + "MP5-KR": "Paragon Soul", + "O-N589": "Paragon Soul", + "ZDYA-G": "Paragon Soul", + "LX5K-W": "Paragon Soul", + "UHKL-N": "Delve", + "Z3V-1W": "Delve", + "A-ELE2": "Delve", + "KFIE-Z": "Delve", + "1DH-SX": "Delve", + "PR-8CA": "Delve", + "NOL-M9": "Delve", + "O-IOAI": "Delve", + "QX-LIJ": "Delve", + "HM-XR2": "Delve", + "4K-TRB": "Delve", + "AJI-MA": "Delve", + "FWST-8": "Delve", + "YZ9-F6": "Delve", + "0N-3RO": "Delve", + "G-TT5V": "Delve", + "319-3D": "Delve", + "I3Q-II": "Delve", + "RF-K9W": "Delve", + "E3OI-U": "Delve", + "IP6V-X": "Delve", + "R5-MM8": "Delve", + "1B-VKF": "Delve", + "T-J6HT": "Delve", + "D-W7F0": "Delve", + "JP4-AA": "Delve", + "FM-JK5": "Delve", + "PDE-U3": "Delve", + "23G-XC": "Delve", + "T5ZI-S": "Delve", + "4X0-8B": "Delve", + "Q-HESZ": "Delve", + "1-SMEB": "Delve", + "M5-CGW": "Delve", + "6Q-R50": "Delve", + "ZA9-PY": "Delve", + "RCI-VL": "Delve", + "MJXW-P": "Delve", + "QC-YX6": "Delve", + "T-M0FA": "Delve", + "4O-239": "Delve", + "LUA5-L": "Delve", + "T-IPZB": "Delve", + "Q-JQSG": "Delve", + "D-3GIQ": "Delve", + "K-6K16": "Delve", + "QY6-RK": "Delve", + "W-KQPI": "Delve", + "PUIG-F": "Delve", + "J-LPX7": "Delve", + "0-HDC8": "Delve", + "F-TE1T": "Delve", + "SVM-3K": "Delve", + "1DQ1-A": "Delve", + "8WA-Z6": "Delve", + "5BTK-M": "Delve", + "N-8YET": "Delve", + "Y-OMTZ": "Delve", + "3-DMQT": "Delve", + "MO-GZ5": "Delve", + "39P-1J": "Delve", + "HZAQ-W": "Delve", + "7G-QIG": "Delve", + "NIDJ-K": "Delve", + "PS-94K": "Delve", + "8RQJ-2": "Delve", + "KEE-N6": "Delve", + "M2-XFE": "Delve", + "5-CQDA": "Delve", + "I-E3TG": "Delve", + "S-6HHN": "Delve", + "ZXB-VC": "Delve", + "GY6A-L": "Delve", + "UEXO-Z": "Delve", + "9O-8W1": "Delve", + "8F-TK3": "Delve", + "PF-KUQ": "Delve", + "N8D9-Z": "Delve", + "F-9PXR": "Delve", + "Y5C-YD": "Delve", + "31X-RE": "Delve", + "Q-02UL": "Delve", + "7UTB-F": "Delve", + "5-6QW7": "Delve", + "7-K6UE": "Delve", + "C6Y-ZF": "Delve", + "6Z-CKS": "Delve", + "G-M5L3": "Delve", + "KBAK-I": "Delve", + "M-SRKS": "Delve", + "9GNS-2": "Delve", + "YAW-7M": "Delve", + "C3N-3S": "Delve", + "CX8-6K": "Delve", + "LWX-93": "Delve", + "1-2J4P": "Delve", + "M0O-JG": "Delve", + "WB-AYY": "Tenerifis", + "BW-WJ2": "Tenerifis", + "S4-9DN": "Tenerifis", + "DT-PXH": "Tenerifis", + "UALX-3": "Tenerifis", + "3L3N-X": "Tenerifis", + "Y-ORBJ": "Tenerifis", + "6-IAFR": "Tenerifis", + "4-P4FE": "Tenerifis", + "RH0-EG": "Tenerifis", + "D-9UEV": "Tenerifis", + "H-HWQR": "Tenerifis", + "QRBN-M": "Tenerifis", + "78R-PI": "Tenerifis", + "ZD1-Z2": "Tenerifis", + "C-FD0D": "Tenerifis", + "S-9RCJ": "Tenerifis", + "ZMV9-A": "Tenerifis", + "FE-6YQ": "Tenerifis", + "W-16DY": "Tenerifis", + "M-4KDB": "Tenerifis", + "C3-0YD": "Tenerifis", + "PDF-3Z": "Tenerifis", + "9-MJVQ": "Tenerifis", + "L2GN-K": "Tenerifis", + "4-IT9G": "Tenerifis", + "PEK-8Z": "Tenerifis", + "2PG-KN": "Tenerifis", + "ABE-M2": "Tenerifis", + "IL-YTR": "Tenerifis", + "KW-OAM": "Tenerifis", + "U2U5-A": "Tenerifis", + "EQWO-Y": "Tenerifis", + "JK-Q77": "Tenerifis", + "QI9-42": "Tenerifis", + "YF-P4X": "Tenerifis", + "JI1-SY": "Tenerifis", + "X-1QGA": "Tenerifis", + "CCE-0J": "Tenerifis", + "T2-V8F": "Tenerifis", + "0VK-43": "Tenerifis", + "TY2X-C": "Tenerifis", + "Q0G-L8": "Tenerifis", + "Q5KZ-W": "Tenerifis", + "WE-KK2": "Tenerifis", + "B8HU-Z": "Tenerifis", + "16AM-3": "Tenerifis", + "A-REKV": "Tenerifis", + "BB-EKF": "Tenerifis", + "DZ6-I5": "Tenerifis", + "R-XDKM": "Tenerifis", + "G1-0UI": "Tenerifis", + "QCDG-H": "Tenerifis", + "XUDX-A": "Tenerifis", + "QLU-P0": "Tenerifis", + "OQTY-Z": "Tenerifis", + "Y-EQ0C": "Tenerifis", + "7M4C-F": "Tenerifis", + "MS1-KJ": "Tenerifis", + "8-BEW8": "Tenerifis", + "NZW-ZO": "Tenerifis", + "WSK-1A": "Tenerifis", + "5-NZNW": "Tenerifis", + "NR8S-Y": "Tenerifis", + "F-ZBO0": "Tenerifis", + "3Q1T-O": "Tenerifis", + "8-4KME": "Tenerifis", + "T6GY-Y": "Tenerifis", + "R1-IMO": "Tenerifis", + "7KIK-H": "Tenerifis", + "B-6STA": "Tenerifis", + "0P-U0Q": "Tenerifis", + "XGH-SH": "Tenerifis", + "G-D0N3": "Tenerifis", + "T-AKQZ": "Tenerifis", + "46DP-O": "Tenerifis", + "9-980U": "Tenerifis", + "EMIG-F": "Tenerifis", + "M-RPN3": "Tenerifis", + "ZO-P5K": "Tenerifis", + "JV1V-O": "Tenerifis", + "9MWZ-B": "Omist", + "LS-QLX": "Omist", + "S-XZHU": "Omist", + "CO-7BI": "Omist", + "ZJG-7D": "Omist", + "C-WPWH": "Omist", + "VULA-I": "Omist", + "R2TJ-1": "Omist", + "G-B3PR": "Omist", + "73-JQO": "Omist", + "XPUM-L": "Omist", + "KR8-27": "Omist", + "LQ-AHE": "Omist", + "LOI-L1": "Omist", + "Y-MSJN": "Omist", + "MJ-X5V": "Omist", + "3FKU-H": "Omist", + "M9-FIB": "Omist", + "D2EZ-X": "Omist", + "DJK-67": "Omist", + "AXDX-F": "Omist", + "J-4FNO": "Omist", + "PEM-LC": "Omist", + "X-EHHD": "Omist", + "6T3I-L": "Omist", + "QSF-EJ": "Omist", + "L-AS00": "Omist", + "NZPK-G": "Omist", + "K-1OY3": "Omist", + "MMUF-8": "Omist", + "99-0GS": "Omist", + "X-3AUU": "Omist", + "H90-C9": "Omist", + "0DD-MH": "Omist", + "RI-JB1": "Omist", + "NQH-MR": "Omist", + "1I6F-9": "Omist", + "Z-7OK1": "Omist", + "UEP0-A": "Omist", + "66-PMM": "Omist", + "OKEO-X": "Omist", + "7-8EOE": "Omist", + "7L9-ZC": "Omist", + "L-YMYU": "Period Basis", + "35-JWD": "Period Basis", + "F-M1FU": "Period Basis", + "0-NTIS": "Period Basis", + "VR-YIQ": "Period Basis", + "XZ-SKZ": "Period Basis", + "I6M-9U": "Period Basis", + "MG0-RD": "Period Basis", + "TPAR-G": "Period Basis", + "VYO-68": "Period Basis", + "TCAG-3": "Period Basis", + "UR-E46": "Period Basis", + "CW9-1Y": "Period Basis", + "1-NJLK": "Period Basis", + "Y-CWQY": "Period Basis", + "8KR9-5": "Period Basis", + "VQE-CN": "Period Basis", + "L5D-ZL": "Period Basis", + "G-C8QO": "Period Basis", + "EIMJ-M": "Period Basis", + "0A-KZ0": "Period Basis", + "E-DOF2": "Period Basis", + "48I1-X": "Period Basis", + "0OTX-J": "Period Basis", + "3OP-3E": "Period Basis", + "JZL-VB": "Period Basis", + "RJ3H-0": "Period Basis", + "08S-39": "Period Basis", + "ZU-MS3": "Period Basis", + "HIX4-H": "Period Basis", + "GR-J8B": "Period Basis", + "OY0-2T": "Period Basis", + "E2-RDQ": "Period Basis", + "TN25-J": "Period Basis", + "PA-VE3": "Period Basis", + "G-Q5JU": "Period Basis", + "RYQC-I": "Period Basis", + "1E-W5I": "Period Basis", + "Z-M5A1": "Period Basis", + "MVUO-F": "Period Basis", + "Luminaire": "Essence", + "Mies": "Essence", + "Oursulaert": "Essence", + "Renyn": "Essence", + "Duripant": "Essence", + "Algogille": "Essence", + "Caslemon": "Essence", + "Jolevier": "Essence", + "Mesybier": "Essence", + "Charmerout": "Essence", + "Yvangier": "Essence", + "Pemene": "Essence", + "Heydieles": "Essence", + "Fliet": "Essence", + "Actee": "Essence", + "Indregulle": "Essence", + "Amane": "Essence", + "Abune": "Essence", + "Deven": "Essence", + "Estaunitte": "Essence", + "Deninard": "Essence", + "Hulmate": "Essence", + "Annages": "Essence", + "Onne": "Essence", + "Vitrauze": "Essence", + "Palmon": "Essence", + "Villore": "Essence", + "Arant": "Essence", + "Allamotte": "Essence", + "Obalyu": "Essence", + "Vifrevaert": "Essence", + "Parts": "Essence", + "Ladistier": "Essence", + "Old Man Star": "Essence", + "Arnon": "Essence", + "Laurvier": "Essence", + "Adirain": "Essence", + "Attyn": "Essence", + "Ignebaener": "Essence", + "Aere": "Essence", + "Lisbaetanne": "Essence", + "Aeschee": "Essence", + "Allebin": "Essence", + "Atlulle": "Essence", + "Droselory": "Essence", + "Haine": "Essence", + "Perckhevin": "Essence", + "Isenan": "Essence", + "Synchelle": "Essence", + "Wysalan": "Essence", + "Yona": "Essence", + "Noghere": "Essence", + "Aporulie": "Essence", + "Seyllin": "Essence", + "Adrel": "Essence", + "Ane": "Essence", + "Clorteler": "Essence", + "Atlangeins": "Essence", + "Derririntel": "Essence", + "Cat": "Essence", + "Ommare": "Essence", + "Andole": "Essence", + "Vale": "Essence", + "Couster": "Essence", + "Hecarrin": "Essence", + "Henebene": "Essence", + "Mesokel": "Essence", + "Fensi": "Kor-Azor", + "Nebian": "Kor-Azor", + "Khabara": "Kor-Azor", + "Jeni": "Kor-Azor", + "Bridi": "Kor-Azor", + "Ami": "Kor-Azor", + "Amdonen": "Kor-Azor", + "Mora": "Kor-Azor", + "Kor-Azor Prime": "Kor-Azor", + "Leva": "Kor-Azor", + "Nishah": "Kor-Azor", + "Masanuh": "Kor-Azor", + "Sehmy": "Kor-Azor", + "Nakregde": "Kor-Azor", + "Danyana": "Kor-Azor", + "Nahyeen": "Kor-Azor", + "Jinkah": "Kor-Azor", + "Nibainkier": "Kor-Azor", + "Polfaly": "Kor-Azor", + "Andrub": "Kor-Azor", + "Kulu": "Kor-Azor", + "Choga": "Kor-Azor", + "Soumi": "Kor-Azor", + "Imih": "Kor-Azor", + "Nare": "Kor-Azor", + "Zinkon": "Kor-Azor", + "Kizama": "Kor-Azor", + "Shaha": "Kor-Azor", + "Neesher": "Kor-Azor", + "Misha": "Kor-Azor", + "Ordion": "Kor-Azor", + "Perbhe": "Kor-Azor", + "Abath": "Kor-Azor", + "Schmaeel": "Kor-Azor", + "Mafra": "Kor-Azor", + "Arzi": "Kor-Azor", + "Kerying": "Kor-Azor", + "Zorenyen": "Kor-Azor", + "Oguser": "Kor-Azor", + "Nahol": "Kor-Azor", + "Tadadan": "Kor-Azor", + "Tralasa": "Kor-Azor", + "Gademam": "Kor-Azor", + "Pananan": "Kor-Azor", + "Daran": "Kor-Azor", + "Latari": "Kor-Azor", + "Shokal": "Kor-Azor", + "Atarli": "Kor-Azor", + "Keproh": "Kor-Azor", + "Zatamaka": "Kor-Azor", + "Rannoze": "Kor-Azor", + "Piri": "Kor-Azor", + "Enal": "Kor-Azor", + "Jedandan": "Kor-Azor", + "Miroona": "Kor-Azor", + "Ranni": "Kor-Azor", + "Arza": "Kor-Azor", + "Liparer": "Kor-Azor", + "Annad": "Kor-Azor", + "Chaktaren": "Kor-Azor", + "Conoban": "Kor-Azor", + "B-B0ME": "Perrigen Falls", + "TDP-T3": "Perrigen Falls", + "H-HGGJ": "Perrigen Falls", + "OJT-J3": "Perrigen Falls", + "A9-F18": "Perrigen Falls", + "DE-IHK": "Perrigen Falls", + "AY9X-Q": "Perrigen Falls", + "XU7-CH": "Perrigen Falls", + "2V-ZHM": "Perrigen Falls", + "V-3K7C": "Perrigen Falls", + "AK-L0Z": "Perrigen Falls", + "R-AG7W": "Perrigen Falls", + "E-WMT7": "Perrigen Falls", + "FLK-LJ": "Perrigen Falls", + "0FG-KS": "Perrigen Falls", + "F-5WYK": "Perrigen Falls", + "EF-QZK": "Perrigen Falls", + "RZ3O-K": "Perrigen Falls", + "LW-YEW": "Perrigen Falls", + "HB-KSF": "Perrigen Falls", + "EH2I-P": "Perrigen Falls", + "OP7-BP": "Perrigen Falls", + "5ZU-VG": "Perrigen Falls", + "6-1T6Z": "Perrigen Falls", + "R-AYGT": "Perrigen Falls", + "G-GRSZ": "Perrigen Falls", + "6-8QLA": "Perrigen Falls", + "5T-A3D": "Perrigen Falls", + "H-FOYG": "Perrigen Falls", + "1A8-6G": "Perrigen Falls", + "PE-SAM": "Perrigen Falls", + "RY-2FX": "Perrigen Falls", + "K-3PQW": "Perrigen Falls", + "4-M1TY": "Perrigen Falls", + "C6CG-W": "Perrigen Falls", + "H-29TM": "Perrigen Falls", + "KOI8-Z": "Perrigen Falls", + "D-QJR9": "Perrigen Falls", + "U4-V3J": "Perrigen Falls", + "B9N2-2": "Perrigen Falls", + "6Q4-X6": "Perrigen Falls", + "BEG-RL": "Perrigen Falls", + "972C-1": "Perrigen Falls", + "U-W436": "Perrigen Falls", + "Z-ENUD": "Perrigen Falls", + "MJ-5F9": "Perrigen Falls", + "M5NO-B": "Perrigen Falls", + "JZ-UQC": "Perrigen Falls", + "JPEZ-R": "Perrigen Falls", + "9WVY-F": "Perrigen Falls", + "7M4-4C": "Perrigen Falls", + "2-YO2K": "Perrigen Falls", + "M-SG47": "Perrigen Falls", + "SR-10Z": "Perrigen Falls", + "W-KXEX": "Perrigen Falls", + "TAL1-3": "Perrigen Falls", + "QHY-RU": "Perrigen Falls", + "7AH-SF": "Perrigen Falls", + "7MMJ-3": "Perrigen Falls", + "PVF-N9": "Perrigen Falls", + "9-EXU9": "Perrigen Falls", + "4-1ECP": "Perrigen Falls", + "UYOC-1": "Perrigen Falls", + "5-U12M": "Perrigen Falls", + "5V-Q1R": "Perrigen Falls", + "M4-KX5": "Perrigen Falls", + "4F9Y-3": "Perrigen Falls", + "MS-RXH": "Perrigen Falls", + "U-3FKL": "Perrigen Falls", + "0XN-SK": "Perrigen Falls", + "J9A-BH": "Perrigen Falls", + "4F6-VZ": "Perrigen Falls", + "B-7LYC": "Perrigen Falls", + "JM0A-4": "Perrigen Falls", + "PT-2KR": "Perrigen Falls", + "L-POLO": "Perrigen Falls", + "8B-A4E": "Perrigen Falls", + "49V-E4": "Perrigen Falls", + "3LL-O0": "Perrigen Falls", + "A1F-22": "Perrigen Falls", + "9-ZA4Z": "Perrigen Falls", + "IU-E9T": "Perrigen Falls", + "NGM-OK": "Perrigen Falls", + "O-QKSM": "Perrigen Falls", + "QKQ3-L": "Perrigen Falls", + "VWES-Y": "Perrigen Falls", + "SY-OLX": "Perrigen Falls", + "XY-ZCI": "Perrigen Falls", + "7JRA-G": "Perrigen Falls", + "W-CSFY": "Perrigen Falls", + "PFV-ZH": "Perrigen Falls", + "L5Y4-M": "Perrigen Falls", + "9IZ-HU": "Perrigen Falls", + "OBV-YC": "Perrigen Falls", + "2AUL-X": "Perrigen Falls", + "F-HQWV": "Perrigen Falls", + "F-A3TR": "Perrigen Falls", + "PA-ALN": "Perrigen Falls", + "01B-88": "Perrigen Falls", + "F18-AY": "Perrigen Falls", + "RZ8A-P": "Perrigen Falls", + "MTO2-2": "Perrigen Falls", + "C3I-D5": "Perrigen Falls", + "0-U2M4": "Perrigen Falls", + "Shera": "Genesis", + "Lor": "Genesis", + "Cleyd": "Genesis", + "Vecamia": "Genesis", + "Ahbazon": "Genesis", + "Atreen": "Genesis", + "Pakhshi": "Genesis", + "Tar": "Genesis", + "Tekaima": "Genesis", + "Manarq": "Genesis", + "Emsar": "Genesis", + "Ourapheh": "Genesis", + "Yulai": "Genesis", + "Tarta": "Genesis", + "Kemerk": "Genesis", + "Nardiarang": "Genesis", + "Ziasad": "Genesis", + "Sibe": "Genesis", + "Makhwasan": "Genesis", + "Zarer": "Genesis", + "Toon": "Genesis", + "Hesarid": "Genesis", + "Ashokon": "Genesis", + "Avyuh": "Genesis", + "Apanake": "Genesis", + "Sheroo": "Genesis", + "Sosh": "Genesis", + "Sigga": "Genesis", + "Keseya": "Genesis", + "Zoohen": "Genesis", + "Serren": "Genesis", + "Hadji": "Genesis", + "Assez": "Genesis", + "Alal": "Genesis", + "Dom-Aphis": "Genesis", + "Iderion": "Genesis", + "Chamja": "Genesis", + "Diaderi": "Genesis", + "Manatirid": "Genesis", + "Pashanai": "Genesis", + "Pamah": "Genesis", + "Leran": "Genesis", + "Beke": "Genesis", + "Malma": "Genesis", + "Noranim": "Genesis", + "Chej": "Genesis", + "Menai": "Genesis", + "Aring": "Genesis", + "Gayar": "Genesis", + "Petidu": "Genesis", + "Naka": "Genesis", + "Madomi": "Genesis", + "Gergish": "Genesis", + "Tahli": "Genesis", + "Imya": "Genesis", + "Kobam": "Genesis", + "Hirizan": "Genesis", + "Anyed": "Genesis", + "Habu": "Genesis", + "Asanot": "Genesis", + "Anzalaisio": "Genesis", + "Chiga": "Genesis", + "Abhan": "Genesis", + "Saphthar": "Genesis", + "Itrin": "Genesis", + "Bantish": "Genesis", + "Korridi": "Genesis", + "Lela": "Genesis", + "Keri": "Genesis", + "Antem": "Genesis", + "Djimame": "Genesis", + "Mozzidit": "Genesis", + "Angur": "Genesis", + "Hangond": "Genesis", + "Access": "Genesis", + "Bherdasopt": "Genesis", + "Gonditsa": "Genesis", + "Simela": "Genesis", + "Shalne": "Genesis", + "Shapisin": "Genesis", + "Olin": "Genesis", + "Galnafsad": "Genesis", + "Otakod": "Genesis", + "Azedi": "Genesis", + "Sharza": "Genesis", + "Pirna": "Genesis", + "Seshi": "Genesis", + "Anara": "Genesis", + "Partod": "Genesis", + "Exit": "Genesis", + "Gateway": "Genesis", + "Central Point": "Genesis", + "Promised Land": "Genesis", + "Dead End": "Genesis", + "New Eden": "Genesis", + "Canard": "Genesis", + "Girani-Fa": "Genesis", + "Nasreri": "Genesis", + "Heorah": "Genesis", + "Ebasez": "Genesis", + "Agal": "Genesis", + "Doza": "Genesis", + "Bania": "Genesis", + "Murethand": "Verge Vendor", + "Melmaniel": "Verge Vendor", + "Ouelletta": "Verge Vendor", + "Costolle": "Verge Vendor", + "Muetralle": "Verge Vendor", + "Loes": "Verge Vendor", + "Tourier": "Verge Vendor", + "Alenia": "Verge Vendor", + "Merolles": "Verge Vendor", + "Alentene": "Verge Vendor", + "Cistuvaert": "Verge Vendor", + "Vaere": "Verge Vendor", + "Aidart": "Verge Vendor", + "Jufvitte": "Verge Vendor", + "Ansalle": "Verge Vendor", + "Scheenins": "Verge Vendor", + "Amygnon": "Verge Vendor", + "Gisleres": "Verge Vendor", + "Ellmay": "Verge Vendor", + "Theruesse": "Verge Vendor", + "Eletta": "Verge Vendor", + "Luse": "Verge Vendor", + "Ekuenbiron": "Verge Vendor", + "Vay": "Verge Vendor", + "Raneilles": "Verge Vendor", + "Hevrice": "Verge Vendor", + "Jovainnon": "Verge Vendor", + "Scolluzer": "Verge Vendor", + "Sortet": "Verge Vendor", + "Claulenne": "Verge Vendor", + "Masalle": "Verge Vendor", + "Annelle": "Verge Vendor", + "Chesiette": "Verge Vendor", + "Reblier": "Verge Vendor", + "Amoderia": "Verge Vendor", + "Arraron": "Verge Vendor", + "Chantrousse": "Verge Vendor", + "Osmomonne": "Verge Vendor", + "Stou": "Verge Vendor", + "Tierijev": "Verge Vendor", + "Adallier": "Verge Vendor", + "Channace": "Verge Vendor", + "Clacille": "Verge Vendor", + "Clellinon": "Verge Vendor", + "Hykanima": "Black Rise", + "Okagaiken": "Black Rise", + "Kehjari": "Black Rise", + "Villasen": "Black Rise", + "Sarenemi": "Black Rise", + "Ashitsu": "Black Rise", + "Korasen": "Black Rise", + "Ienakkamon": "Black Rise", + "Kinakka": "Black Rise", + "Raihbaka": "Black Rise", + "Innia": "Black Rise", + "Iralaja": "Black Rise", + "Martoh": "Black Rise", + "Eha": "Black Rise", + "Pavanakka": "Black Rise", + "Uchomida": "Black Rise", + "Samanuni": "Black Rise", + "Astoh": "Black Rise", + "Onnamon": "Black Rise", + "Rohamaa": "Black Rise", + "Uuhulanen": "Black Rise", + "Tsuruma": "Black Rise", + "Ahtila": "Black Rise", + "Ichoriya": "Black Rise", + "Okkamon": "Black Rise", + "Vaaralen": "Black Rise", + "Asakai": "Black Rise", + "Prism": "Black Rise", + "Mushikegi": "Black Rise", + "Teskanen": "Black Rise", + "Elunala": "Black Rise", + "Ikoskio": "Black Rise", + "Hikkoken": "Black Rise", + "Enaluri": "Black Rise", + "Aivonen": "Black Rise", + "Hallanen": "Black Rise", + "Akidagi": "Black Rise", + "Immuri": "Black Rise", + "Nennamaila": "Black Rise", + "Hirri": "Black Rise", + "Kedama": "Black Rise", + "Oinasiken": "Black Rise", + "Notoras": "Black Rise", + "Rakapas": "Black Rise", + "Teimo": "Black Rise", + "Iwisoda": "Black Rise", + "Nisuwa": "Black Rise", + "Pynekastoh": "Black Rise", + "Reitsato": "Black Rise" +} + +import logging + +def buildUpperKeyedAliases(): + """Return a dictionary of systems keyed on their upper case name. + Each entry is a dictionary with name and region fields in standardized DOTLAN case + """ + systems = dict() + for s in SYSTEMS: + value = { 'name': s, 'region': SYSTEMS[s] } + upper = s.upper() + systems[upper] = value + + if '-' in upper: + # - short with - (minus), I-I will match I43-IF3 + parts = upper.split("-") + if len(parts) != 2: + logging.critical("Unexpected number of dashes in system name [%s]", s) + systems[parts[0][0]+':'+parts[1][0]] = value + # also add systems removing dashes + nodash = upper.replace("-", "") + systems[nodash] = value + + if '0' in upper: + ohs = upper.replace("0","O") + systems[ohs] = value + + if 'O' in upper: + zeros = upper.replace("O","0") + systems[zeros] = value + + return systems diff --git a/src/vi/threads.py b/src/vi/threads.py index f42c9e9..596814d 100755 --- a/src/vi/threads.py +++ b/src/vi/threads.py @@ -38,9 +38,9 @@ def __init__(self): self.active = True - def addChatEntry(self, chatEntry, clearCache=False): + def addChatEntry(self, chatEntry, clearAvatarCacheForUser=False): try: - if clearCache: + if clearAvatarCacheForUser: cache = Cache() cache.removeAvatar(chatEntry.message.user) @@ -78,6 +78,7 @@ def run(self): lastCall = time.time() if avatar: cache.putAvatar(charname, avatar) + logging.debug("AvatarFindThread storing avatar for %s" % charname) if avatar: logging.debug("AvatarFindThread emit avatar_update for %s" % charname) self.emit(SIGNAL("avatar_update"), chatEntry, avatar) diff --git a/src/vi/ui/ChatroomsChooser.ui b/src/vi/ui/ChatroomsChooser.ui deleted file mode 100644 index 4e4fb40..0000000 --- a/src/vi/ui/ChatroomsChooser.ui +++ /dev/null @@ -1,66 +0,0 @@ - - - Dialog - - - - 0 - 0 - 556 - 197 - - - - Chatrooms - - - - - - - - Enter the chatrooms to watch into the following field. Separate them by comma. - - - Qt::PlainText - - - true - - - - - - - - - - - - Restore Defaults - - - - - - - Cancel - - - - - - - Save - - - - - - - - - - - - diff --git a/src/vi/ui/JumpbridgeChooser.ui b/src/vi/ui/JumpbridgeChooser.ui deleted file mode 100644 index f6d233c..0000000 --- a/src/vi/ui/JumpbridgeChooser.ui +++ /dev/null @@ -1,106 +0,0 @@ - - - Dialog - - - - 0 - 0 - 696 - 394 - - - - Jumpbridge Data - - - - - - - - - - - Path to the Data - - - - - - For example: http://example.org/jumpbridge_data.txt - - - - - - - - - Please enter the URL to the Jumpbridge data: - - - - - - - - - - - - - - - - - - - - - Format of the jumpbridge data: - - - - - - QPlainTextEdit::NoWrap - - - true - - - - - - - - - - - - - - - - - - Cancel - - - - - - - Save - - - - - - - - - - - diff --git a/src/vi/ui/MainWindow.ui b/src/vi/ui/MainWindow.ui index d3a9ccd..d7296e8 100644 --- a/src/vi/ui/MainWindow.ui +++ b/src/vi/ui/MainWindow.ui @@ -37,16 +37,7 @@ - - 0 - - - 0 - - - 0 - - + 0 @@ -72,16 +63,7 @@ - - 0 - - - 0 - - - 0 - - + 0 @@ -255,19 +237,10 @@ All Intel (past 20 minutes) - - 5 - - - 5 - - - 5 - - + 5 - + 5 @@ -341,15 +314,15 @@ 0 0 936 - 22 + 21 - Kos + File - - + + @@ -360,7 +333,6 @@ Chat - @@ -376,15 +348,15 @@ Region - - - + + + Other Region... + + - - - + - + @@ -399,10 +371,18 @@ + + + K.O.S. + + + + + @@ -521,11 +501,8 @@ - - true - - Other Region... + Custom Region... @@ -533,9 +510,9 @@ Sound Setup... - + - Jumpbridge Data... + Flush Cache @@ -584,59 +561,9 @@ Transparency - - - true - + - Providence - - - providence - - - - - true - - - Catch - - - catch - - - - - true - - - Provi / Catch - - - providencecatch - - - - - true - - - Provi / Catch (compact) - - - Providence-catch - - - - - true - - - Querious - - - querious + Settings @@ -644,7 +571,7 @@ QWebView QWidget -
QtWebKitWidgets/QWebView
+
QtWebKit/QWebView
PanningWebView diff --git a/src/vi/ui/SettingsTabs.ui b/src/vi/ui/SettingsTabs.ui new file mode 100644 index 0000000..7b4be63 --- /dev/null +++ b/src/vi/ui/SettingsTabs.ui @@ -0,0 +1,389 @@ + + + Dialog + + + + 0 + 0 + 640 + 480 + + + + Settings + + + + + 0 + 0 + 640 + 480 + + + + + 0 + 0 + + + + TabWidget + + + 1 + + + + + 0 + 0 + + + + Quick Setup + + + + + 10 + 10 + 611 + 431 + + + + + + + Paste the quick setup text here that was provided by your alliance, corporation, ... + + + Qt::PlainText + + + true + + + + + + + + + + + + Undo + + + + + + + Apply + + + + + + + + + + + Jumpbridges + + + + + 10 + 0 + 611 + 453 + + + + + QLayout::SetMaximumSize + + + + + + + + 0 + 0 + + + + Setup jumpbridges to be displayed on the map. You can setup a url with your own data or include a DOTLAN jumpbridge id. + + + + + + + + + + 0 + 0 + + + + + + + + 0 + 0 + + + + false + + + Please enter the URL to the Jumpbridge data (i.e. http://example.org/jumpbridge_data.txt): + + + false + + + false + + + + + 10 + 24 + 571 + 221 + + + + + + + + + + true + + + + 0 + 0 + + + + + 0 + 100 + + + + Qt::ScrollBarAlwaysOn + + + Qt::ScrollBarAlwaysOff + + + QPlainTextEdit::WidgetWidth + + + true + + + How to format the data for the jumpbridges: + +Put all the jumpbridges in one single textfile, wher a line in the file represents a jumpbridge. + +The line contains the first system, the connection between the systems and the second system. Between the three parts hast to be a space. + +The connection is a line (minus) in the middle and possible arrows (sign for greater or lower) at the ends. If there is such a sign, an arrow will be drawn on the map. + +Examples: + +System1 <-> System2 +System3 <- System4 +System5 - System6 + +The first line will draw a jumpbridge between System1 and System2 with an arrow on both sides. +The second line will draw a jumpbridge between System3 and System4, but only the side to System3 will have an arrow pointing on the system (could be helpfull for "oneway"-jumpbridges). +The last line draws a line between System5 and System 6 and no arrows at the endpoints. + +Write the systemnames as they are written in the maps. + +Don't forget the space between the System names and the jumpbridge! + + + + + + + + + + + + + + + 0 + 0 + + + + + + + + 0 + 0 + + + + + 0 + 48 + + + + Use Jumpbridge Info from Dotlan + + + false + + + false + + + + + + QLayout::SetDefaultConstraint + + + 6 + + + + + + 0 + 5 + + + + Dotlan Jumpbridge Id + + + + + + + + 0 + 0 + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + + + + + + + + Undo + + + + + + + Apply + + + + + + + + + + + Chat Channels + + + + + 10 + 10 + 611 + 431 + + + + + + + Enter the channels to watch below. Separate them by comma. + + + Qt::PlainText + + + true + + + + + + + + + + + + Restore Defaults + + + + + + + Undo + + + + + + + Apply + + + + + + + + + + + + + diff --git a/src/vi/ui/viui.py b/src/vi/ui/viui.py index a253f1e..1aa39c7 100644 --- a/src/vi/ui/viui.py +++ b/src/vi/ui/viui.py @@ -21,6 +21,8 @@ import sys import time import six +import json +import traceback import requests import webbrowser @@ -34,18 +36,19 @@ from PyQt4.QtWebKit import QWebPage from vi import amazon_s3, evegate from vi import dotlan, filewatcher -from vi import states +from vi import states, systems from vi.cache.cache import Cache from vi.resources import resourcePath from vi.soundmanager import SoundManager from vi.threads import AvatarFindThread, KOSCheckerThread, MapStatisticsThread from vi.ui.systemtray import TrayContextMenu from vi.chatparser import ChatParser +from vi.regions import REGIONS from PyQt4.QtGui import QAction from PyQt4.QtGui import QMessageBox # Timer intervals -MESSAGE_EXPIRY_SECS = 20 * 60 +MESSAGE_EXPIRY_SECS = 60 * 60 * 1 MAP_UPDATE_INTERVAL_MSECS = 4 * 1000 CLIPBOARD_CHECK_INTERVAL_MSECS = 4 * 1000 @@ -83,6 +86,10 @@ def __init__(self, pathToLogs, trayIcon, backGroundColor): self.scanIntelForKosRequestsEnabled = True self.initialMapPosition = None self.mapPositionsDict = {} + self.chatparser = None + self.systemsWithRegions = systems.buildUpperKeyedAliases() + + self.chatbox.setTitle("All Intel (past {0} minues)".format(str(MESSAGE_EXPIRY_SECS/60))) # Load user's toon names self.knownPlayerNames = self.cache.getFromCache("known_player_names") @@ -94,12 +101,12 @@ def __init__(self, pathToLogs, trayIcon, backGroundColor): QMessageBox.warning(None, "Known Characters not Found", diagText, "Ok") # Set up user's intel rooms - roomnames = self.cache.getFromCache("room_names") + roomnames = self.cache.getConfigValue("channel_names") if roomnames: roomnames = roomnames.split(",") else: roomnames = (u"TheCitadel", u"North Provi Intel", u"North Catch Intel", "North Querious Intel") - self.cache.putIntoCache("room_names", u",".join(roomnames), 60 * 60 * 24 * 365 * 5) + self.cache.saveConfigValue("channel_names", u",".join(roomnames)) self.roomnames = roomnames # Disable the sound UI if sound is not available @@ -134,7 +141,10 @@ def __init__(self, pathToLogs, trayIcon, backGroundColor): self.wireUpUIConnections() self.recallCachedSettings() self.setupThreads() + self.updateRegionMenu() + self.updateOtherRegionMenu() self.setupMap(True) + self.replayLogs() def paintEvent(self, event): @@ -143,6 +153,27 @@ def paintEvent(self, event): painter = QPainter(self) self.style().drawPrimitive(QStyle.PE_Widget, opt, painter, self) + def wheelEvent(self,event): + if event.modifiers() & QtCore.Qt.ControlModifier: + steps = event.delta() // 120 + vector = steps and steps // abs(steps) # 0, 1, or -1 + for step in range(1, abs(steps) + 1): + self.mapView.setZoomFactor(self.mapView.zoomFactor() + vector * 0.1) + + def keyPressEvent(self, event): + key = event.key() + if key == QtCore.Qt.Key_0: + if event.modifiers() & QtCore.Qt.ControlModifier: + self.mapView.setZoomFactor(1.0) + elif key == QtCore.Qt.Key_Plus or key == QtCore.Qt.Key_Equal: + if event.modifiers() & QtCore.Qt.ControlModifier: + self.mapView.setZoomFactor(self.mapView.zoomFactor() + 0.1) + elif key == QtCore.Qt.Key_Minus or key == QtCore.Qt.Key_Underscore: + if event.modifiers() & QtCore.Qt.ControlModifier: + self.mapView.setZoomFactor(self.mapView.zoomFactor() - 0.1) + elif key == QtCore.Qt.Key_J: + self.changeJumpbridgesVisibility() + def recallCachedSettings(self): try: @@ -152,6 +183,42 @@ def recallCachedSettings(self): # todo: add a button to delete the cache / DB self.trayIcon.showMessage("Settings error", "Something went wrong loading saved state:\n {0}".format(str(e)), 1) + def updateOtherRegionMenu(self): + for region in REGIONS: + menuItem = self.otherRegionSubmenu.addAction(region) + receiver = lambda region=region: self.onRegionSelect(region) + self.connect(menuItem, SIGNAL('triggered()'), receiver) + self.otherRegionSubmenu.addAction(menuItem) + + def updateRegionMenu(self): + quick_regions = self.cache.getConfigValue("quick_regions") + if quick_regions: + j = json.loads(quick_regions) + for old_item in self.menuRegion.actions(): + if "Other Region..." == old_item.text(): + orm = self.menuRegion.insertSeparator(old_item) + break + self.menuRegion.removeAction(old_item) + for r in j: + if not 'label' in r: + self.trayIcon.showMessage("Quick regions error", "No label field in :\n {0}".format(str(r)), 1) + label = r['label'] + if label.startswith('-'): + menuItem = self.menuRegion.insertSeparator(orm) + continue + if 'region' in r: + region = r['region'] + else: + region = label + menuItem = self.menuRegion.addAction(label) + receiver = lambda region=region: self.onRegionSelect(region) + self.connect(menuItem, SIGNAL('triggered()'), receiver) + self.menuRegion.insertAction(orm, menuItem) + + def onRegionSelect(self, region): + logging.info("NEW REGION: [%s]", region) + Cache().saveConfigValue("region_name", region) + self.handleRegionChosen() def wireUpUIConnections(self): # Wire up general UI connections @@ -167,12 +234,6 @@ def wireUpUIConnections(self): self.connect(self.infoAction, SIGNAL("triggered()"), self.showInfo) self.connect(self.showChatAvatarsAction, SIGNAL("triggered()"), self.changeShowAvatars) self.connect(self.alwaysOnTopAction, SIGNAL("triggered()"), self.changeAlwaysOnTop) - self.connect(self.chooseChatRoomsAction, SIGNAL("triggered()"), self.showChatroomChooser) - self.connect(self.catchRegionAction, SIGNAL("triggered()"), lambda : self.handleRegionMenuItemSelected(self.catchRegionAction)) - self.connect(self.providenceRegionAction, SIGNAL("triggered()"), lambda : self.handleRegionMenuItemSelected(self.providenceRegionAction)) - self.connect(self.queriousRegionAction, SIGNAL("triggered()"), lambda : self.handleRegionMenuItemSelected(self.queriousRegionAction)) - self.connect(self.providenceCatchRegionAction, SIGNAL("triggered()"), lambda : self.handleRegionMenuItemSelected(self.providenceCatchRegionAction)) - self.connect(self.providenceCatchCompactRegionAction, SIGNAL("triggered()"), lambda : self.handleRegionMenuItemSelected(self.providenceCatchCompactRegionAction)) self.connect(self.chooseRegionAction, SIGNAL("triggered()"), self.showRegionChooser) self.connect(self.showChatAction, SIGNAL("triggered()"), self.changeChatVisibility) self.connect(self.soundSetupAction, SIGNAL("triggered()"), self.showSoundSetup) @@ -184,7 +245,8 @@ def wireUpUIConnections(self): self.connect(self.frameButton, SIGNAL("clicked()"), self.changeFrameless) self.connect(self.quitAction, SIGNAL("triggered()"), self.close) self.connect(self.trayIcon, SIGNAL("quit"), self.close) - self.connect(self.jumpbridgeDataAction, SIGNAL("triggered()"), self.showJumbridgeChooser) + self.connect(self.settingsAction, SIGNAL("triggered()"), self.showSettings) + self.connect(self.flushCacheAction, SIGNAL("triggered()"), self.flushCache) self.mapView.page().scrollRequested.connect(self.mapPositionChanged) @@ -217,7 +279,7 @@ def setupMap(self, initialize=False): self.filewatcherThread.paused = True logging.info("Finding map file") - regionName = self.cache.getFromCache("region_name") + regionName = self.cache.getConfigValue("region_name") if not regionName: regionName = "Providence" svg = None @@ -233,6 +295,11 @@ def setupMap(self, initialize=False): logging.error(e) QMessageBox.critical(None, "Error getting map", six.text_type(e), "Quit") sys.exit(1) + except Exception as e: + self.cache.deleteFromCache("region_name") + logging.error(e) + QMessageBox.critical(None, "Error setting up map", six.text_type(e), "Quit") + sys.exit(1) if self.dotlan.outdatedCacheError: e = self.dotlan.outdatedCacheError @@ -244,10 +311,19 @@ def setupMap(self, initialize=False): # Load the jumpbridges logging.critical("Load jump bridges") - self.setJumpbridges(self.cache.getFromCache("jumpbridge_url")) + self.setJumpbridges(self.cache.getConfigValue("jumpbridge_url")) + self.systems = self.dotlan.systems + logging.critical("Creating chat parser") - self.chatparser = ChatParser(self.pathToLogs, self.roomnames, self.systems) + oldParser = self.chatparser + self.chatparser = ChatParser(self.pathToLogs, self.roomnames, self.systemsWithRegions, MESSAGE_EXPIRY_SECS) + if oldParser: + scrollPosition = self.chatListWidget.verticalScrollBar().value() + self.chatListWidget.clear() + self.processLogMessages(oldParser.knownMessages) + self.chatListWidget.verticalScrollBar().setSliderPosition(scrollPosition) + self.chatparser.knownMessages = oldParser.knownMessages # Menus - only once if initialize: @@ -263,19 +339,6 @@ def mapContextMenuEvent(event): # Clicking links self.mapView.connect(self.mapView, SIGNAL("linkClicked(const QUrl&)"), self.mapLinkClicked) - # Also set up our app menus - if not regionName: - self.providenceCatchRegionAction.setChecked(True) - elif regionName.startswith("Providencecatch"): - self.providenceCatchRegionAction.setChecked(True) - elif regionName.startswith("Catch"): - self.catchRegionAction.setChecked(True) - elif regionName.startswith("Providence"): - self.providenceRegionAction.setChecked(True) - elif regionName.startswith("Querious"): - self.queriousRegionAction.setChecked(True) - else: - self.chooseRegionAction.setChecked(True) self.jumpbridgesButton.setChecked(False) self.statisticsButton.setChecked(False) @@ -284,6 +347,7 @@ def mapContextMenuEvent(event): self.updateMapView() self.setInitialMapPositionForRegion(regionName) self.mapTimer.start(MAP_UPDATE_INTERVAL_MSECS) + # Allow the file watcher to run now that all else is set up self.filewatcherThread.paused = False logging.critical("Map setup complete") @@ -342,7 +406,7 @@ def closeEvent(self, event): (None, "changeUseSpokenNotifications", self.useSpokenNotificationsAction.isChecked()), (None, "changeKosCheckClipboard", self.kosClipboardActiveAction.isChecked()), (None, "changeAutoScanIntel", self.scanIntelForKosRequestsEnabled)) - self.cache.putIntoCache("settings", str(settings), 60 * 60 * 24 * 30) + self.cache.saveConfigValue("settings", str(settings)) # Stop the threads try: @@ -526,8 +590,24 @@ def mapLinkClicked(self, url): def markSystemOnMap(self, systemname): - self.systems[six.text_type(systemname)].mark() - self.updateMapView() + n = six.text_type(systemname) + if n in self.systems: + self.systems[n].mark() + self.updateMapView() + elif n.upper() in self.systemsWithRegions: + logging.warn('System [%s] is in another region [%s]', + self.systemsWithRegions[n]['name'], self.systemsWithRegions[n]['region']) + ans = QMessageBox.question(self, + u"System not on current map", + u"{0} is in {1}. Would you like to view the {1} map?".format( + six.text_type(self.systemsWithRegions[n]['name']), + six.text_type(self.systemsWithRegions[n]['region'])), + QMessageBox.Ok, QMessageBox.Cancel) + if QMessageBox.Ok == ans: + self.onRegionSelect(self.systemsWithRegions[n]['region']) + self.markSystemOnMap(systemname) + else: + logging.warn('System [%s] is unknown.', n) def setLocation(self, char, newSystem): @@ -535,7 +615,7 @@ def setLocation(self, char, newSystem): system.removeLocatedCharacter(char) if not newSystem == "?" and newSystem in self.systems: self.systems[newSystem].addLocatedCharacter(char) - self.setMapContent(self.dotlan.svg) + self.updateMapView() def setMapContent(self, content): @@ -561,7 +641,7 @@ def loadInitialMapPositions(self, newDictionary): def setInitialMapPositionForRegion(self, regionName): try: if not regionName: - regionName = self.cache.getFromCache("region_name") + regionName = self.cache.getConfigValue("region_name") if regionName: xy = self.mapPositionsDict[regionName] self.initialMapPosition = QPoint(xy[0], xy[1]) @@ -570,30 +650,27 @@ def setInitialMapPositionForRegion(self, regionName): def mapPositionChanged(self, dx, dy, rectToScroll): - regionName = self.cache.getFromCache("region_name") + regionName = self.cache.getConfigValue("region_name") if regionName: scrollPosition = self.mapView.page().mainFrame().scrollPosition() self.mapPositionsDict[regionName] = (scrollPosition.x(), scrollPosition.y()) - def showChatroomChooser(self): - chooser = ChatroomsChooser(self) + def showSettings(self): + chooser = Settings(self) chooser.connect(chooser, SIGNAL("rooms_changed"), self.changedRoomnames) - chooser.show() - - - def showJumbridgeChooser(self): - url = self.cache.getFromCache("jumpbridge_url") - chooser = JumpbridgeChooser(self, url) chooser.connect(chooser, SIGNAL("set_jumpbridge_url"), self.setJumpbridges) chooser.show() + def flushCache(self): + self.cache.flush() def setSoundVolume(self, value): SoundManager().setSoundVolume(value) def setJumpbridges(self, url): + if url is None: url = "" try: @@ -607,37 +684,36 @@ def setJumpbridges(self, url): else: data = amazon_s3.getJumpbridgeData(self.dotlan.region.lower()) self.dotlan.setJumpbridges(data) - self.cache.putIntoCache("jumpbridge_url", url, 60 * 60 * 24 * 365 * 8) + self.cache.saveConfigValue("jumpbridge_url", url) except Exception as e: QMessageBox.warning(None, "Loading jumpbridges failed!", "Error: {0}".format(six.text_type(e)), "OK") def handleRegionMenuItemSelected(self, menuAction=None): - self.catchRegionAction.setChecked(False) - self.providenceRegionAction.setChecked(False) - self.queriousRegionAction.setChecked(False) - self.providenceCatchRegionAction.setChecked(False) - self.providenceCatchCompactRegionAction.setChecked(False) - self.chooseRegionAction.setChecked(False) if menuAction: - menuAction.setChecked(True) regionName = six.text_type(menuAction.property("regionName").toString()) regionName = dotlan.convertRegionName(regionName) - Cache().putIntoCache("region_name", regionName, 60 * 60 * 24 * 365) + Cache().saveConfigValue("region_name", regionName) self.setupMap() + def handleRegionChosen(self): + self.setupMap() def showRegionChooser(self): - def handleRegionChosen(): - self.handleRegionMenuItemSelected(None) - self.chooseRegionAction.setChecked(True) - self.setupMap() - - self.chooseRegionAction.setChecked(False) chooser = RegionChooser(self) - self.connect(chooser, SIGNAL("new_region_chosen"), handleRegionChosen) + self.connect(chooser, SIGNAL("new_region_chosen"), self.handleRegionChosen) chooser.show() + def replayLogs(self): + """On startup, replay info from logfiles""" + messages = [] + for path in self.chatparser.rewind(): + messages.extend(self.chatparser.fileModified(path)) + messages.sort(key=lambda x: x.timestamp) + # we use these parsed messages to replay events on region switch, reset them to a time ordered list + self.chatparser.knownMessages = messages + self.processLogMessages(messages) + logging.critical("Done with replay") def addMessageToIntelChat(self, message): scrollToBottom = False @@ -658,6 +734,7 @@ def addMessageToIntelChat(self, message): def pruneMessages(self): + self.chatparser.expire() try: now = time.mktime(evegate.currentEveTime().timetuple()) for row in range(self.chatListWidget.count()): @@ -701,7 +778,7 @@ def showKosResult(self, state, text, requestType, hasKos): def changedRoomnames(self, newRoomnames): - self.cache.putIntoCache("room_names", u",".join(newRoomnames), 60 * 60 * 24 * 365 * 5) + self.cache.saveConfigValue("channel_names", u",".join(newRoomnames)) self.chatparser.rooms = newRoomnames @@ -738,7 +815,7 @@ def systemTrayActivated(self, reason): def updateAvatarOnChatEntry(self, chatEntry, avatarData): updated = chatEntry.updateAvatar(avatarData) if not updated: - self.avatarFindThread.addChatEntry(chatEntry, clearCache=True) + self.avatarFindThread.addChatEntry(chatEntry) # , clearCache=True) else: self.emit(SIGNAL("avatar_loaded"), chatEntry.message.user, avatarData) @@ -770,7 +847,14 @@ def zoomMapOut(self): def logFileChanged(self, path): messages = self.chatparser.fileModified(path) + self.processLogMessages(messages) + + def processLogMessages(self, messages): for message in messages: + + # This function is a resource pig, give others a chance to run while we process messages + time.sleep(0) + # If players location has changed if message.status == states.LOCATION: self.knownPlayerNames.add(message.user) @@ -789,11 +873,13 @@ def logFileChanged(self, path): self.addMessageToIntelChat(message) # For each system that was mentioned in the message, check for alarm distance to the current system # and alarm if within alarm distance. - systemList = self.dotlan.systems if message.systems: - for system in message.systems: - systemname = system.name - systemList[systemname].setStatus(message.status) + for systemname in message.systems: + if not systemname in self.systems: + logging.debug("No dotlan match for system [%s], maybe it's not shown right now:", systemname) + continue + system = self.systems[systemname] + system.setStatus(message.status, message.timestamp) if message.status in (states.REQUEST, states.ALARM) and message.user not in self.knownPlayerNames: alarmDistance = self.alarmDistance if message.status == states.ALARM else 0 for nSystem, data in system.getNeighbours(alarmDistance).items(): @@ -801,33 +887,10 @@ def logFileChanged(self, path): chars = nSystem.getLocatedCharacters() if len(chars) > 0 and message.user not in chars: self.trayIcon.showNotification(message, system.name, ", ".join(chars), distance) - self.setMapContent(self.dotlan.svg) - - -class ChatroomsChooser(QtGui.QDialog): - def __init__(self, parent): - QtGui.QDialog.__init__(self, parent) - uic.loadUi(resourcePath("vi/ui/ChatroomsChooser.ui"), self) - self.connect(self.defaultButton, SIGNAL("clicked()"), self.setDefaults) - self.connect(self.cancelButton, SIGNAL("clicked()"), self.accept) - self.connect(self.saveButton, SIGNAL("clicked()"), self.saveClicked) - cache = Cache() - roomnames = cache.getFromCache("room_names") - if not roomnames: - roomnames = u"TheCitadel,North Provi Intel,North Catch Intel,North Querious Intel" - self.roomnamesField.setPlainText(roomnames) - - - def saveClicked(self): - text = six.text_type(self.roomnamesField.toPlainText()) - rooms = [six.text_type(name.strip()) for name in text.split(",")] - self.accept() - self.emit(SIGNAL("rooms_changed"), rooms) - - - def setDefaults(self): - self.roomnamesField.setPlainText(u"TheCitadel,North Provi Intel,North Catch Intel,North Querious Intel") + system.messages.append(message) + # call once after all messages are processed + self.updateMapView() class RegionChooser(QtGui.QDialog): def __init__(self, parent): @@ -836,7 +899,7 @@ def __init__(self, parent): self.connect(self.cancelButton, SIGNAL("clicked()"), self.accept) self.connect(self.saveButton, SIGNAL("clicked()"), self.saveClicked) cache = Cache() - regionName = cache.getFromCache("region_name") + regionName = cache.getConfigValue("region_name") if not regionName: regionName = u"Providence" self.regionNameField.setPlainText(regionName) @@ -848,7 +911,7 @@ def saveClicked(self): self.regionNameField.setPlainText(text) correct = False try: - url = dotlan.Map.DOTLAN_BASIC_URL.format(text) + url = dotlan.dotlan_url(text) content = requests.get(url).text if u"not found" in content: correct = False @@ -868,7 +931,7 @@ def saveClicked(self): logging.error(e) correct = False if correct: - Cache().putIntoCache("region_name", text, 60 * 60 * 24 * 365) + Cache().saveConfigValue("region_name", text) self.accept() self.emit(SIGNAL("new_region_chosen")) @@ -882,13 +945,16 @@ def __init__(self, parent, chatType, selector, chatEntries, knownPlayerNames): self.parent = parent self.chatType = 0 self.selector = selector - self.chatEntries = [] - for entry in chatEntries: - self.addChatEntry(entry) titleName = "" + self.chatEntries = [] if self.chatType == SystemChat.SYSTEM: - titleName = self.selector.name self.system = selector + systemDisplayName = self.system.name + if systemDisplayName in parent.systemsWithRegions: + systemDisplayName = parent.systemsWithRegions[systemDisplayName]['name'] + titleName = "%s [%s]" % (systemDisplayName, self.selector.secondaryInfo) + for entry in chatEntries: + self.addChatEntry(entry) for name in knownPlayerNames: self.playerNamesBox.addItem(name) self.setWindowTitle("Chat for {0}".format(titleName)) @@ -917,10 +983,12 @@ def _addMessageToChat(self, message, avatarPixmap): def addChatEntry(self, entry): if self.chatType == SystemChat.SYSTEM: message = entry.message - avatarPixmap = entry.avatarLabel.pixmap() - if self.selector in message.systems: - self._addMessageToChat(message, avatarPixmap) - + try: + avatarPixmap = entry.avatarLabel.pixmap() + if self.system.name in message.systems: + self._addMessageToChat(message, avatarPixmap) + except: + pass def locationSet(self): char = six.text_type(self.playerNamesBox.currentText()) @@ -992,7 +1060,10 @@ def updateAvatar(self, avatarData): if pixmap.isNull(): return False scaledAvatar = pixmap.scaled(32, 32) - self.avatarLabel.setPixmap(scaledAvatar) + try: + self.avatarLabel.setPixmap(scaledAvatar) + except: + pass return True @@ -1002,24 +1073,100 @@ def changeFontSize(self, newSize): self.textLabel.setFont(font) -class JumpbridgeChooser(QtGui.QDialog): - def __init__(self, parent, url): +class Settings(QtGui.QDialog): + def __init__(self, parent): QtGui.QDialog.__init__(self, parent) - uic.loadUi(resourcePath("vi/ui/JumpbridgeChooser.ui"), self) - self.connect(self.saveButton, SIGNAL("clicked()"), self.savePath) - self.connect(self.cancelButton, SIGNAL("clicked()"), self.accept) - self.urlField.setText(url) + uic.loadUi(resourcePath("vi/ui/SettingsTabs.ui"), self) + self.cache = Cache() + self.parent = parent + self.tabs.setCurrentIndex(0) # load displaying first tab, regardless of which page was last open in designer + + # Chatrooms + self.connect(self.chatDefaultButton, SIGNAL("clicked()"), self.setChatToDefaults) + self.connect(self.chatCancelButton, SIGNAL("clicked()"), self.resetChatSettings) + self.connect(self.chatSaveButton, SIGNAL("clicked()"), self.saveChatSettings) + self.resetChatSettings() + + # JBS + self.connect(self.jbSaveButton, SIGNAL("clicked()"), self.saveJbs) + self.connect(self.jbCancelButton, SIGNAL("clicked()"), self.resetJbs) + self.resetJbs() # loading format explanation from textfile - with open(resourcePath("docs/jumpbridgeformat.txt")) as f: - self.formatInfoField.setPlainText(f.read()) + # with open(resourcePath("docs/jumpbridgeformat.txt")) as f: + # self.formatInfoField.setPlainText(f.read()) + # Quick Setup + self.connect(self.quickSettingsSaveButton, SIGNAL("clicked()"), self.saveQuickSettings) + self.connect(self.quickSettingsCancelButton, SIGNAL("clicked()"), self.resetQuickSettings) + self.resetQuickSettings() - def savePath(self): + def resetJbs(self): + self.jbUrlField.setText(self.cache.getConfigValue("jumpbridge_url")) + self.jbIdField.setText(self.cache.getConfigValue("dotlan_jb_id")) + + def saveJbs(self): try: - url = six.text_type(self.urlField.text()) + url = six.text_type(self.jbUrlField.text()) if url != "": requests.get(url).text + self.cache.saveConfigValue("dotlan_jb_id", six.text_type(self.jbIdField.text())) self.emit(SIGNAL("set_jumpbridge_url"), url) - self.accept() except Exception as e: QMessageBox.critical(None, "Finding Jumpbridgedata failed", "Error: {0}".format(six.text_type(e)), "OK") + + def resetChatSettings(self): + roomnames = self.cache.getConfigValue("channel_names") + if not roomnames: + self.setChatToDefaults() + else: + self.roomnamesField.setPlainText(roomnames) + + def saveChatSettings(self): + text = six.text_type(self.roomnamesField.toPlainText()) + rooms = [six.text_type(name.strip()) for name in text.split(",")] + self.emit(SIGNAL("rooms_changed"), rooms) + + def setChatToDefaults(self): + roomnames = self.cache.getConfigValue("default_room_names") + if not roomnames: + self.roomnamesField.setPlainText(u"TheCitadel,North Provi Intel,North Catch Intel,North Querious Intel") + else: + self.roomnamesField.setPlainText(roomnames) + + def resetQuickSettings(self): + self.quickSettingsField.setPlainText("") + + def saveQuickSettings(self): + try: + d = json.loads(six.text_type(self.quickSettingsField.toPlainText())) + if not dict: + QMessageBox.critical(None, "Could not parse input field", "Error: {0}".format(six.text_type(d)), "OK") + return + + if 'channels' in d: + self.cache.saveConfigValue('default_room_names', ",".join(d['channels'])) + self.emit(SIGNAL("rooms_changed"), d['channels']) + + if 'dotlan_jb_id' in d: + self.cache.saveConfigValue("dotlan_jb_id", d['dotlan_jb_id']) + + if 'jumpbridge_url' in d: + self.emit(SIGNAL("set_jumpbridge_url"), d['jumpbridge_url']) + + if 'kos_url' in d: + self.cache.saveConfigValue("kos_url", d['kos_url']) + + if 'region_name' in d: + self.cache.saveConfigValue("region_name", d['region_name']) + self.parent.handleRegionChosen() + + if 'quick_regions' in d: + self.cache.saveConfigValue("quick_regions", json.dumps(d['quick_regions'])) + self.parent.updateRegionMenu() + + self.resetChatSettings() + self.resetJbs() + + except Exception as e: + traceback.print_exc() + QMessageBox.critical(None, "Saving quick settings failed", "Error: {0}".format(six.text_type(e)), "OK") diff --git a/src/vintel.py b/src/vintel.py index 2ebbc95..5b8572a 100644 --- a/src/vintel.py +++ b/src/vintel.py @@ -56,13 +56,20 @@ class Application(QApplication): def __init__(self, args): super(Application, self).__init__(args) + self.setWindowIcon(QtGui.QIcon('icon.ico')) + # windows silliness to set taskbar icon + if sys.platform.startswith("win32"): + import ctypes + myappid = u'eve.vintel.' + version.VERSION + ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID(myappid) + # Set up paths chatLogDirectory = "" if len(sys.argv) > 1: chatLogDirectory = sys.argv[1] if not os.path.exists(chatLogDirectory): - if sys.platform.startswith("darwin"): + if sys.platform.startswith("darwin") or sys.platform.startswith("cygwin"): chatLogDirectory = os.path.join(os.path.expanduser("~"), "Documents", "EVE", "logs", "Chatlogs") if not os.path.exists(chatLogDirectory): chatLogDirectory = os.path.join(os.path.expanduser("~"), "Library", "Application Support", "Eve Online", @@ -71,10 +78,12 @@ def __init__(self, args): chatLogDirectory = os.path.join(os.path.expanduser("~"), "EVE", "logs", "Chatlogs") elif sys.platform.startswith("win32") or sys.platform.startswith("cygwin"): import ctypes.wintypes + from win32com.shell import shellcon buf = ctypes.create_unicode_buffer(ctypes.wintypes.MAX_PATH) - ctypes.windll.shell32.SHGetFolderPathW(0, 5, 0, 0, buf) - documentsPath = buf.value - chatLogDirectory = os.path.join(documentsPath, "EVE", "logs", "Chatlogs") + hResult = ctypes.windll.shell32.SHGetFolderPathW(0, shellcon.CSIDL_PERSONAL, 0, 0, buf) + if hResult == 0: + documentsPath = buf.value + chatLogDirectory = os.path.join(documentsPath, "EVE", "logs", "Chatlogs") if not os.path.exists(chatLogDirectory): # None of the paths for logs exist, bailing out QMessageBox.critical(None, "No path to Logs", "No logs found at: " + chatLogDirectory, "Quit") @@ -93,10 +102,10 @@ def __init__(self, args): splash = QtGui.QSplashScreen(QtGui.QPixmap(resourcePath("vi/ui/res/logo.png"))) vintelCache = Cache() - logLevel = vintelCache.getFromCache("logging_level") + logLevel = vintelCache.getConfigValue("logging_level") if not logLevel: logLevel = logging.WARN - backGroundColor = vintelCache.getFromCache("background_color") + backGroundColor = vintelCache.getConfigValue("background_color") if backGroundColor: self.setStyleSheet("QWidget { background-color: %s; }" % backGroundColor) @@ -137,4 +146,3 @@ def __init__(self, args): app = Application(sys.argv) sys.exit(app.exec_()) - diff --git a/src/vintel.spec b/src/vintel.spec index 6bf561b..62fd559 100644 --- a/src/vintel.spec +++ b/src/vintel.spec @@ -19,11 +19,9 @@ a = Analysis(['vintel.py'], pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher) a.datas += [('vi/ui/MainWindow.ui', 'vi/ui/MainWindow.ui', 'DATA'), - ('vi/ui/SystemChat.ui', 'vi/ui/SystemChat.ui', 'DATA'), + ('vi/ui/SettingsTabs.ui', 'vi/ui/SettingsTabs.ui', 'DATA'), ('vi/ui/ChatEntry.ui', 'vi/ui/ChatEntry.ui', 'DATA'), ('vi/ui/Info.ui', 'vi/ui/Info.ui', 'DATA'), - ('vi/ui/ChatroomsChooser.ui', 'vi/ui/ChatroomsChooser.ui', 'DATA'), - ('vi/ui/RegionChooser.ui', 'vi/ui/RegionChooser.ui', 'DATA'), ('vi/ui/SoundSetup.ui', 'vi/ui/SoundSetup.ui', 'DATA'), ('vi/ui/JumpbridgeChooser.ui', 'vi/ui/JumpbridgeChooser.ui', 'DATA'), ('vi/ui/res/qmark.png', 'vi/ui/res/qmark.png', 'DATA'),