import os, zlib, json, re, time, glob, requests, uuid
from pathlib import Path
# from kodi_six import xbmc, xbmcvfs, xbmcgui, xbmcaddon
import xbmc, xbmcvfs, xbmcgui, xbmcaddon
from dateutil import parser as date_parser
from collections import defaultdict
import xml.etree.ElementTree as ET
from urllib.parse import quote_plus as url_quote
from urllib.parse import unquote_plus as url_unquote
from . import xmltodict

ADDON_NAME = 'plugin.program.iagl'
WINDOW_ID = xbmcgui.getCurrentWindowId()
HOME_ID = 10000
ADDON_HANDLE = xbmcaddon.Addon(id=ADDON_NAME)
ADDON_TITLE = ADDON_HANDLE.getAddonInfo('name')
RESET_DIRECTORY_CACHE_TIME = 43200 #Rescan userdata directory every 12 hours unless otherwise updated, this to catch any game cache that needs to be purged
# CHUNK_SIZE = 1024
CHUNK_SIZE = 10485760 #10MB
HEADER_SIZE = 6000 #6kb
MAX_ART = 11 #Max number of arts in the xml files
TEXT_ENCODING='UTF-8'
NOTIFICATION_DEINIT_TIME = 300 #Time to wait after closing a notification for it to de-init
WAIT_FOR_PLAYER_TIME = 5000 #Time to wait after sending retroplayer play command to check status
WAIT_FOR_PROCESS_EXIT = 3 #Time in seconds to wait for subprocess to exit
IGNORE_THESE_FILETYPES = ['srm','sav','fs','state','auto','xml','nfo','.srm','.sav','.fs','.state','.auto','.xml','.nfo'] #Matching filetypes to ignore for re-launching
IGNORE_THESE_FILES = ['win31.bat'] #Matching files to ignore for re-launching
ARCHIVE_FILETYPES = ['001','7z','bz2','cbr','gz','iso','rar','tar','tarbz2','targz','tarxz','tbz2','tgz','xz','zip','.001', '.7z', '.bz2', '.cbr', '.gz', '.iso', '.rar', '.tar', '.tarbz2', '.targz', '.tarxz', '.tbz2', '.tgz', '.xz', '.zip']
re_game_tags = re.compile(r'\([^)]*\)')
re_game_codes = re.compile(r'\[[^)]*\]')
re_clean_alphanumeric = re.compile(r'([^\s\w]|_)+')

def get_mem_cache(key):
	if xbmcgui.Window(HOME_ID).getProperty(key):
		if key=='iagl_directory':
			dict_out = json.loads(xbmcgui.Window(HOME_ID).getProperty(key))
			#Retranslate all paths back into PosixPath
			dict_out['addon']['dat_files']['path'] = Path(dict_out['addon']['dat_files']['path'])
			dict_out['addon']['dat_files']['files'] = [Path(x) for x in dict_out['addon']['dat_files']['files']]
			dict_out['addon']['databases']['path'] = Path(dict_out['addon']['databases']['path'])
			dict_out['addon']['databases']['files'] = [Path(x) for x in dict_out['addon']['databases']['files']]
			dict_out['addon']['templates']['path'] = Path(dict_out['addon']['templates']['path'])
			dict_out['addon']['templates']['files'] = [Path(x) for x in dict_out['addon']['templates']['files']]
			dict_out['userdata']['game_cache']['path'] = Path(dict_out['userdata']['game_cache']['path'])
			dict_out['userdata']['game_cache']['files'] = [Path(x) for x in dict_out['userdata']['game_cache']['files']]
			dict_out['userdata']['game_cache']['folders'] = [Path(x) for x in dict_out['userdata']['game_cache']['folders']]
			dict_out['userdata']['list_cache']['path'] = Path(dict_out['userdata']['list_cache']['path'])
			dict_out['userdata']['list_cache']['files'] = [Path(x) for x in dict_out['userdata']['list_cache']['files']]
			dict_out['userdata']['dat_files']['path'] = Path(dict_out['userdata']['dat_files']['path'])
			dict_out['userdata']['dat_files']['files'] = [Path(x) for x in dict_out['userdata']['dat_files']['files']]
			return dict_out
		elif key in ['iagl_current_games_list','iagl_current_games_stats_list','iagl_current_game_id','iagl_current_game_list_id','TextViewer_Header','TextViewer_Text','iagl_script_started','iagl_version','iagl_start_time']: #String props
			return xbmcgui.Window(HOME_ID).getProperty(key)
		else: #JSON Props
			return json.loads(xbmcgui.Window(HOME_ID).getProperty(key))
	else:
		return None

def clear_mem_cache(key):
	xbmcgui.Window(HOME_ID).clearProperty(key)
	return True

def set_mem_cache(key,dict_in):
	success = False
	if isinstance(dict_in,dict) or isinstance(dict_in,list):
		xbmcgui.Window(HOME_ID).setProperty(key,json.dumps(dict_in,cls=iagl_encoder))
		success = True
	if isinstance(dict_in,str):
		xbmcgui.Window(HOME_ID).setProperty(key,dict_in)
		success = True
	return success

def set_disc_cache(file_in,games_in,stats_in):
	success = False
	if isinstance(stats_in,dict) and isinstance(games_in,list):
		if not check_if_file_exists(file_in):
			with xbmcvfs.File(str(file_in),'wb') as fi:
				json.dump([games_in,stats_in],fi)
		else:
			xbmc.log(msg='IAGL:  The cache file %(value_in)s already exists'%{'value_in':os.path.split(file_in)[-1]}, level=xbmc.LOGDEBUG)
		success = True
	elif isinstance(stats_in,dict) and games_in is None:
		if not check_if_file_exists(file_in):
			with xbmcvfs.File(str(file_in),'wb') as fi:
				json.dump(stats_in,fi)
		else:
			xbmc.log(msg='IAGL:  The stats cache file %(value_in)s already exists'%{'value_in':os.path.split(file_in)[-1]}, level=xbmc.LOGDEBUG)
		success = True
	return success

def get_disc_cache(file_in):
	with xbmcvfs.File(str(file_in),'rb') as fi:
		disc_cache = json.load(fi)
	if '_stats' in file_in:
		return disc_cache
	else:
		return disc_cache[0],disc_cache[1]

def flatten_list(list_in):
	if isinstance(list_in,list):
		try:
			return [item for sublist in list_in for item in sublist]
		except:
			return list_in
	else:
		return list_in

class iagl_encoder(json.JSONEncoder):
	def default(self, obj):
		if isinstance(obj, Path): # Need to translate PosixPath to string for encoding
			return str(obj)
		return json.JSONEncoder.default(self, obj)

def check_userdata_directory(dir_in):
	if check_if_dir_exists(dir_in):
		return Path(xbmcvfs.translatePath(str(dir_in)))
	else:
		if xbmcvfs.mkdir(str(dir_in)):
			xbmc.log(msg='IAGL:  Created directory %(value_in)s'%{'value_in':os.path.split(str(dir_in))[-1]}, level=xbmc.LOGDEBUG)
			return Path(xbmcvfs.translatePath(str(dir_in)))
		else:
			xbmc.log(msg='IAGL:  Unable to create directory %(value_in)s'%{'value_in':os.path.split(dir_in)[-1]}, level=xbmc.LOGERROR)
			return None

def check_if_dir_exists(dir_in):
	if isinstance(dir_in,str):
		return xbmcvfs.exists(os.path.join(dir_in,''))
	elif isinstance(dir_in,Path):
		return dir_in.exists()
	else:
		return False

def check_if_file_exists(file_in):
	if isinstance(file_in,str):
		return xbmcvfs.exists(file_in)
	elif isinstance(file_in,Path):
		return file_in.exists()
	else:
		return False

def get_setting_as(setting_type=None,setting=None):
	if setting_type is not None and setting is not None:
		if setting_type == 'int':
			return int(setting)
		elif setting_type == 'bool':
			if setting.lower().strip() in ['true','enabled','show','0','visible']:
				return True
			else:
				return False
		elif setting_type == 'file_path':
			if setting and isinstance(setting,str) and Path(setting).is_file():
				return Path(setting)
			else:
				return None
		elif setting_type == 'dir_path':
			if setting and isinstance(setting,str) and Path(setting).is_dir():
				return Path(setting)
			else:
				return None
		elif setting_type == 'emulator_type':
			setting_map = {'0':'fs_uae',
						   '1':'pj_64',
						   '2':'dolphin',
						   '3':'mame',
						   '4':'demul',
						   '5':'epsxe'}
			return setting_map.get(setting)
		elif setting_type == 'emulator_name':
			setting_map = {'0':'FS-UAE',
						   '1':'Project 64',
						   '2':'Dolphin',
						   '3':'MAME',
						   '4':'DEMUL',
						   '5':'ePSXe'}
			return setting_map.get(setting)
		elif setting_type == 'emulator_cmd_rep':
			setting_map = {'0':'%APP_PATH_FS_UAE%',
						   '1':'%APP_PATH_PJ64%',
						   '2':'%APP_PATH_DOLPHIN%',
						   '3':'%APP_PATH_MAME%',
						   '4':'%APP_PATH_DEMUL%',
						   '5':'%APP_PATH_EPSXE%'}
			return setting_map.get(setting)
		elif setting_type == 'index_list_route':
			setting_map = {'1':'/archives/Browse All Lists',
						   '2':'/archives/Browse by Category',
						   '3':'/Favorites',
						   '4':'/Search',
						   '5':'/archives/Choose from List'}
			if setting_map.get(setting):
				return setting_map.get(setting)
			else:
				return setting_map.get('5')
		elif setting_type == 'set_content':
			setting_map = {'0':'movies',
						   '1':'tvshows',
						   '2':'videos',
						   '3':'mixed',
						   '4':'games',
						   '5':'None'}
			if setting_map.get(setting):
				return setting_map.get(setting)
			else:
				return setting_map.get('1')	
		elif setting_type == 'game_list_route':
			setting_map = {'0':'list_all',
						   '1':'choose_from_list',
						   '2':'Alphabetical',
						   '3':'Group by Genres',
						   '4':'Group by Years',
						   '5':'Group by Players',
						   '6':'Group by Studio',
						   '7':'Group by Tag',
						   '8':'Group by Custom Groups'}
			if setting_map.get(setting):
				return setting_map.get(setting)
			else:
				return setting_map.get('0')		   
		elif setting_type == 'game_naming_convention':
			setting_map = {'0':'%(title)s',
						   '1':'%(title)s | %(genre)s',
						   '2':'%(title)s | %(date)s',
						   '3':'%(title)s | %(nplayers)s',
						   '4':'%(title)s | %(genre)s | %(date)s',
						   '5':'%(title)s | %(genre)s | %(size)s',
						   '6':'%(title)s | %(genre)s | %(nplayers)s',
						   '7':'%(title)s | %(date)s | %(size)s',
						   '8':'%(title)s | %(date)s | %(nplayers)s',
						   '9':'%(genre)s | %(title)s',
						   '10':'%(date)s | %(title)s',
						   '11':'%(nplayers)s | %(title)s',
						   '12':'%(genre)s | %(title)s | %(date)s',
						   '13':'%(date)s | %(title)s | %(genre)s',
						   '14':'%(nplayers)s | %(title)s | %(genre)s',
						   '15':'%(nplayers)s | %(title)s | %(date)s',
						   '16':'%(title)s | %(genre)s | %(date)s | %(tag)s',
						   '17':'%(title)s | %(genre)s | %(date)s | %(nplayers)s',
						   '18':'%(title)s | %(genre)s | %(nplayers)s | %(tag)s',
						   '19':'%(title)s | %(genre)s | %(date)s | %(size)s'}
			if setting_map.get(setting):
				return setting_map.get(setting)
			else:
				return setting_map.get('0')	
		elif setting_type == 'games_per_page':
			setting_map = {'0':10,
						   '1':25,
						   '2':50,
						   '3':100,
						   '4':150,
						   '5':200,
						   '6':250,
						   '7':300,
						   '8':350,
						   '9':400,
						   '10':450,
						   '11':500}
			if setting_map.get(setting):
				return setting_map.get(setting)
			else:
				return None	   
		elif setting_type == 'forced_viewtype':
			setting_map = {'0': 0,
						 '1': '50',
						 '2': '51',
						 '3': '52',
						 '4': '501',
						 '5': '502',
						 '6': '503',
						 '7': '504',
						 '8': '505',
						 '9': '53',
						 '10': '54',
						 '11': '55',
						 '12': '506',
						 '13': '56',
						 '14': '57',
						 '15': '58',
						 '16': '59',
						 '17': '66',
						 '18': '69',
						 '19': '95',
						 '20': '97',
						 '21': '507',
						 '22': '508',
						 '23': '509',
						 '24': '510',
						 '25': '511',
						 '26': '512',
						 '27': '513',
						 '28': '514',
						 '29': '515',
						 '30': '516',
						 '31': '517',
						 '32': '518',
						 '33': '519',
						 '34': '520',
						 '35': '521',
						 '36': '522',
						 '37': '523',
						 '38': '524',
						 '39': '525',
						 '40': '500',
						 '41': '583',
						 '42': '588'}
			if setting_map.get(setting):
				return setting_map.get(setting)
			else:
				return 0
		elif setting_type == 'ext_launch_env':
			setting_map = {'1':'OSX',
						   '2':'linux',
						   '3':'windows',
						   '4':'android',
						   '5':'android_aarch64',
						   '6':'android_ra32'}
			return setting_map.get(setting)
		elif setting_type == 'display_date_format':
			if isinstance(setting,dict) and setting.get('result') and setting.get('result').get('value') and setting.get('result').get('value') != 'regional':
				return setting.get('result').get('value').replace('DD','%d').replace('MM','%m').replace('YYYY','%Y').replace('D','%-d').replace('M','%-m').replace('YYYY','%Y')
			else:
				return '%x'
	else:
		return None

def get_post_dl_commands():
	return dict(zip(['none','unzip_rom','unzip_and_launch_file','unzip_to_folder_and_launch_file','unzip_and_launch_scummvm_file','unzip_and_launch_win31_file'],['None (Direct File Launch)','UnArchive Game','UnArchive Game, Launch File','UnArchive Game to Folder, Launch File','UnArchive Game, Generate SCUMMVM File','UnArchive Game, Generate WIN31 BAT File']))

def get_downloadpath(path=None,default=None):
	if path=='default' or path is None:
		return default
	else:
		return Path(xbmcvfs.translatePath(path))

def zachs_debug(message=None,level_in=xbmc.LOGWARNING):
	if message is not None:
		xbmc.log(msg='*IAGL TEST*:  %(value_in)s' % {'value_in': message}, level=level_in)

def get_launch_parameter(setting_in=None,retun_val=None):
	if isinstance(setting_in,str) or isinstance(setting_in,Path):
		return str(setting_in)
	else:
		return return_val

def move_file(file_in=None,path_in=None):
	success = False
	if file_in is not None and path_in is not None:
		if check_if_file_exists(file_in):
			success = xbmcvfs.rename(str(file_in),os.path.join(path_in,file_in.name))
			if not success: #Per docs note moving files between different filesystem (eg. local to nfs://) is not possible on all platforms. You may have to do it manually by using the copy and deleteFile functions.
				xbmc.log(msg='IAGL:  Unable to move file %(value_in_1)s to %(value_in_2)s, attempting copy / delete'%{'value_in_1':file_in,'value_in_2':path_in}, level=xbmc.LOGDEBUG)
				if xbmcvfs.copy(str(file_in),os.path.join(path_in,file_in.name)):
					success = xbmcvfs.delete(str(file_in))
	if success:
		xbmc.log(msg='IAGL:  Moved file %(value_in_1)s to %(value_in_2)s'%{'value_in_1':file_in,'value_in_2':path_in}, level=xbmc.LOGDEBUG)
	return success

def delete_file_pathlib(file_in=None,confirm_delete=False):
	success = False
	if file_in.is_file():
		if not confirm_delete:
			try:
				file_in.unlink()
				success = True
			except Exception as exc:
				xbmc.log(msg='IAGL:  Error deleting file %(value_in)s.  Exception %(exc)s' % {'value_in': file_in, 'exc': exc}, level=xbmc.LOGERROR)
				success = False
		else:
			if xbmcgui.Dialog().yesno('Confirm Deletion','Are you sure you want to delete the file %(file_in)s'%{'file_in':file_in.name},'Cancel','Delete'): #Need to localize this eventually
				try:
					file_in.unlink()
					success = True
				except Exception as exc:
					xbmc.log(msg='IAGL:  Error deleting file %(value_in)s.  Exception %(exc)s' % {'value_in': file_in, 'exc': exc}, level=xbmc.LOGERROR)
					success = False
	if success:
		xbmc.log(msg='IAGL:  Deleted file %(value_in)s'%{'value_in':file_in}, level=xbmc.LOGDEBUG)
	return success

def delete_folder_pathlib(folder_in=None,confirm_delete=False):
	success = False
	if folder_in.is_dir():
		if not confirm_delete:
			try:
				folder_in.rmdir()
				success = True
			except Exception as exc:
				xbmc.log(msg='IAGL:  Error deleting folder %(value_in)s.  Exception %(exc)s' % {'value_in': folder_in, 'exc': exc}, level=xbmc.LOGERROR)
				success = False
		else:
			if xbmcgui.Dialog().yesno('Confirm Deletion','Are you sure you want to delete the folder %(folder_in)s'%{'folder_in':folder_in.name},'Cancel','Delete'): #Need to localize this eventually
				try:
					folder_in.rmdir()
					success = True
				except Exception as exc:
					xbmc.log(msg='IAGL:  Error deleting folder %(value_in)s.  Exception %(exc)s' % {'value_in': folder_in, 'exc': exc}, level=xbmc.LOGERROR)
					success = False
	if success:
		xbmc.log(msg='IAGL:  Deleted folder %(value_in)s'%{'value_in':folder_in}, level=xbmc.LOGDEBUG)
	return success

def delete_file(file_in=None,confirm_delete=False):
	success = False
	if file_in is not None:
		if check_if_file_exists(file_in):
			if not confirm_delete:
				success = xbmcvfs.delete(str(file_in))
			else:
				if xbmcgui.Dialog().yesno('Confirm Deletion','Are you sure you want to delete %(file_in)s'%{'file_in':file_in.name},'Cancel','Delete'): #Need to localize this eventually
					success = xbmcvfs.delete(str(file_in))
	if success:
		xbmc.log(msg='IAGL:  Deleted file %(value_in_1)s'%{'value_in_1':file_in}, level=xbmc.LOGDEBUG)
	return success

def read_xml_file(file_in):
	if check_if_file_exists(file_in):
		with xbmcvfs.File(str(file_in)) as fi:
			try:
				return xmltodict.parse(bytes(fi.readBytes()))
			except Exception as exc:
				xbmc.log(msg='IAGL:  Error reading xml file %(value_in)s.  Exception %(exc)s' % {'value_in': file_in, 'exc': exc}, level=xbmc.LOGERROR)
				return None
	else:
		xbmc.log(msg='IAGL:  Error xml file %(value_in)s does not exist' % {'value_in': file_in}, level=xbmc.LOGERROR)
		return None

def read_xml_games(file_in):
	if check_if_file_exists(file_in):
		with xbmcvfs.File(str(file_in)) as fi:
			try:
				games_out = xmltodict.parse(bytes(fi.readBytes())).get('datafile').get('game')
				if isinstance(games_out,list):
					return games_out
				else:
					return [games_out]
			except Exception as exc:
				xbmc.log(msg='IAGL:  Error reading games xml file %(value_in)s.  Exception %(exc)s' % {'value_in': file_in, 'exc': exc}, level=xbmc.LOGERROR)
				return None
	else:
		xbmc.log(msg='IAGL:  Error games xml file %(value_in)s does not exist' % {'value_in': file_in}, level=xbmc.LOGERROR)
		return None

def read_xml_file_et(file_in):
	if check_if_file_exists(file_in):
		with xbmcvfs.File(str(file_in)) as fi:
			try:
				return etree_to_dict(ET.parse(fi).getroot())
			except Exception as exc:
				xbmc.log(msg='IAGL:  Error reading xml file %(value_in)s.  Exception %(exc)s' % {'value_in': file_in, 'exc': exc}, level=xbmc.LOGERROR)
				return None
	else:
		xbmc.log(msg='IAGL:  Error xml file %(value_in)s does not exist' % {'value_in': file_in}, level=xbmc.LOGERROR)
		return None

def get_xml_games(file_in):
	games_out = get_xml_games_path_et(file_in) #Try getting xml header from path (fast)
	# games_out = get_xml_games_path_xmltodict(file_in) #Try getting xml header from path (fast)
	if games_out:
		return games_out
	else:
		return get_xml_games_xbmcvfs_et(str(file_in)) #If it fails, use xbmcvfs (slower)
		# return get_xml_games_xbmcvfs_xmltodict(str(file_in)) #If it fails, use xbmcvfs (slower)

def get_xml_games_path_et(file_in):
	if check_if_file_exists(file_in):
		with file_in.open(mode='rb') as f:
			return [etree_to_dict(x).get('game') for x in ET.parse(f).getroot().iter('game')]
			# return [dict(zip(['@name']+[y.tag for y in list(x)],[x.get('name')]+[y.text for y in list(x)])) for x in ET.parse(f).getroot().iter('game')]
	else:
		xbmc.log(msg='IAGL:  Error xml file %(value_in)s does not exist' % {'value_in': file_in.name}, level=xbmc.LOGERROR)
		return None

def get_xml_games_path_xmltodict(file_in):
	if check_if_file_exists(file_in):
		with file_in.open(mode='rb') as f:
			games_out = xmltodict.parse(f).get('datafile').get('game')
		if isinstance(games_out,list):
			return games_out
		else:
			return [games_out]
	else:
		xbmc.log(msg='IAGL:  Error xml file %(value_in)s does not exist' % {'value_in': file_in.name}, level=xbmc.LOGERROR)
		return None

def get_xml_games_xbmcvfs_et(file_in):
	if check_if_file_exists(file_in):
		with xbmcvfs.File(str(file_in)) as fi:
			try:
				return [etree_to_dict(x).get('game') for x in ET.parse(fi).getroot().iter('game')]
			except Exception as exc:
				xbmc.log(msg='IAGL:  Error reading xml file %(value_in)s.  Exception %(exc)s' % {'value_in': file_in, 'exc': exc}, level=xbmc.LOGERROR)
				return None
	else:
		xbmc.log(msg='IAGL:  Error xml file %(value_in)s does not exist' % {'value_in': file_in}, level=xbmc.LOGERROR)
		return None

def split_value(value_in):
	if isinstance(value_in,str):
		return [x.strip() for x in value_in.split(',') if x]
	else:
		return None

def combine_value(value_in):
	if isinstance(value_in,list):
		return ','.join(value_in)
	elif isinstance(value_in,str):
		return value_in
	else:
		return None

def get_game_tags(value_in):
	if isinstance(value_in,str):
		return [x.strip() for x in flatten_list([x.replace('(','').replace(')','').split(',') for x in re_game_tags.findall(value_in)])]
	else:
		return None

def get_game_size(value_in):
	if isinstance(value_in,dict):
		return sum(map(int,[x.get('@size') for x in [value_in] if x and x.get('@size')]))
	elif isinstance(value_in,list):
		return sum(map(int,[x.get('@size') for x in value_in if x and x.get('@size')]))
	else:
		return None

def map_database_listitem_dict(dict_in,default_dict,game_list_name,type_in=None):
	props = None
	if type_in is None:
		label2 = dict_in.get('label') #We will use label2 to carry the next route by default
	if dict_in.get('localization'):
		localized_label = loc_str(int(dict_in.get('localization')))
	else:
		localized_label = dict_in.get('label')
	if game_list_name is None:
		if dict_in.get('plot') and dict_in.get('plot').isdigit():
			plot = loc_str(int(dict_in.get('plot')))
		else:
			plot = dict_in.get('plot')
	else:
		if dict_in.get('plot') and dict_in.get('plot').isdigit():
			plot = '%(label)s for %(game_list_name)s'%{'label':loc_str(int(dict_in.get('plot'))),'game_list_name':game_list_name}
		else:
			plot = '%(label)s for %(game_list_name)s'%{'label':dict_in.get('plot'),'game_list_name':game_list_name}
	if dict_in.get('sort'):
		props = {'SpecialSort':dict_in.get('sort')}
	return {'values': {'label':localized_label,'label2':label2},
			'info':   {'originaltitle':localized_label,'title':localized_label,'plot':plot,'trailer':choose_trailer(dict_in.get('trailer'),default_dict.get('trailer'))},
			'art':    {'poster':choose_image(dict_in.get('thumb'),default_dict.get('thumb')),
					   'banner':choose_image(dict_in.get('banner'),default_dict.get('banner')),
					   'fanart':choose_image(dict_in.get('fanart'),default_dict.get('fanart')),
					   'clearlogo':choose_image(dict_in.get('logo'),default_dict.get('logo')),
					   'icon':choose_image(dict_in.get('logo'),default_dict.get('logo')),
					   'thumb':choose_image(dict_in.get('thumb'),default_dict.get('thumb')),
					   },
			'properties':props,
			}

def clean_query_values(value_in):
	if not value_in:
		return 'All'
	elif isinstance(value_in,list):
		return ', '.join(value_in)
	else:
		return value_in

def map_search_random_listitem_dict(dict_in,default_dict,search_query,type_in=None):
	if type_in is None:
		label2 = dict_in.get('label2') #We will use label2 to carry the next route by default
	if isinstance(search_query,dict) and search_query.get(dict_in.get('label2')):
		if isinstance(search_query.get(dict_in.get('label2')),list):
			label_value = ', '.join(search_query.get(dict_in.get('label2')))
		else:
			label_value = search_query.get(dict_in.get('label2'))
		label = '%(label)s[CR][COLOR FF12A0C7]%(value)s[/COLOR]'%{'label':dict_in.get('label'),'value':label_value}
		plot = '%(label)s[CR][CR]Current Setting:[CR]%(value)s'%{'label':dict_in.get('plot'),'value':label_value}
	else:
		label = dict_in.get('label')
		plot = dict_in.get('plot')
	if dict_in.get('label2') in ['execute','execute_link']:
		query_summary_map = {'lists':'Game Lists','genre':'Genres','nplayers':'Players','year':'Years','studio':'Studios','tag':'Tags','groups':'Custom Groups','title':'Title','num_of_results':'Number of Results'}
		if isinstance(search_query,dict):
			xbmc.log(msg='IAGL:  Search Query Mapping:', level=xbmc.LOGDEBUG)
			xbmc.log(msg='IAGL:  %(mapping)s'%{'mapping':['%(item)s: %(values)s'%{'item':query_summary_map.get(k),'values':clean_query_values(v)} for k,v in search_query.items() if k in query_summary_map.keys()]}, level=xbmc.LOGDEBUG)
			label_value = '[CR]'.join(['%(item)s: %(values)s'%{'item':query_summary_map.get(k),'values':clean_query_values(v)} for k,v in search_query.items() if k in query_summary_map.keys()])
			plot = '%(label)s%(query_string)s %(total)s[CR][CR]%(value)s'%{'label':dict_in.get('plot'),'query_string':loc_str(30394),'total':next(iter([x for x in [search_query.get('game_count')] if x]),'Unknown'),'value':label_value}
		return {'values': {'label':label,'label2':label2},
				'info':   {'originaltitle':dict_in.get('label'),'title':dict_in.get('label'),'plot':plot,'trailer':choose_trailer(dict_in.get('trailer'),default_dict.get('trailer'))},
				'art':    {'poster':choose_image(dict_in.get('thumb'),default_dict.get('thumb')),
						   'banner':choose_image(dict_in.get('banner'),default_dict.get('banner')),
						   'fanart':choose_image(dict_in.get('fanart'),default_dict.get('fanart')),
						   'clearlogo':choose_image(dict_in.get('logo'),default_dict.get('logo')),
						   'icon':choose_image(dict_in.get('logo'),default_dict.get('logo')),
						   'thumb':choose_image(dict_in.get('thumb'),default_dict.get('thumb')),
						   },
				'properties': {'query' : json.dumps(search_query)}
				}
	else:
		return {'values': {'label':label,'label2':label2},
				'info':   {'originaltitle':dict_in.get('label'),'title':dict_in.get('label'),'plot':plot,'trailer':choose_trailer(dict_in.get('trailer'),default_dict.get('trailer'))},
				'art':    {'poster':choose_image(dict_in.get('thumb'),default_dict.get('thumb')),
						   'banner':choose_image(dict_in.get('banner'),default_dict.get('banner')),
						   'fanart':choose_image(dict_in.get('fanart'),default_dict.get('fanart')),
						   'clearlogo':choose_image(dict_in.get('logo'),default_dict.get('logo')),
						   'icon':choose_image(dict_in.get('logo'),default_dict.get('logo')),
						   'thumb':choose_image(dict_in.get('thumb'),default_dict.get('thumb')),
						   },
				}

def map_game_list_listitem_dict(dict_in,default_dict,fn_in,type_in=None):
	if type_in is None:
		label2 = fn_in #We will use label2 to carry the next route by default
	return {'values': {'label':dict_in.get('emu_name'),'label2':label2},
			'info':   {'title':dict_in.get('emu_name'),
					   'originaltitle':dict_in.get('emu_name'),
					   'date':get_date(dict_in.get('emu_date')),
					   'credits':dict_in.get('emu_author'),
					   'plot':dict_in.get('emu_comment'),
					   'tag':'Launch using %(value_in)s'%{'value_in':dict_in.get('emu_launcher')},
					   'genre':split_value(dict_in.get('emu_category')),
					   'trailer':choose_trailer(dict_in.get('emu_trailer'))},
						# 'size' : game_lists_dict.get('dat_filesize')[aa]
			'art':    {'poster':choose_image(dict_in.get('emu_thumb'),default_dict.get('thumb')),
					   'banner':choose_image(dict_in.get('emu_banner'),default_dict.get('banner')),
					   'fanart':choose_image(dict_in.get('emu_fanart'),default_dict.get('fanart')),
					   'clearlogo':choose_image(dict_in.get('emu_logo')),
					   'icon':choose_image(dict_in.get('emu_logo')),
					   'thumb':choose_image(dict_in.get('emu_thumb'),default_dict.get('thumb'))},
		'properties': {'emu_visibility' : dict_in.get('emu_visibility'),
						'emu_category' : dict_in.get('emu_category'),
						'emu_description' : dict_in.get('emu_description'),
						'emu_version' : dict_in.get('emu_version'),
						'emu_date' : dict_in.get('emu_date'),
						'emu_baseurl' : dict_in.get('emu_baseurl'),
						'emu_launcher' : dict_in.get('emu_launcher'),
						'emu_ext_launch_cmd' : dict_in.get('emu_ext_launch_cmd'),
						'emu_default_addon' : dict_in.get('emu_default_addon'),
						'emu_downloadpath' : dict_in.get('emu_downloadpath'),
						'emu_comment' : dict_in.get('emu_comment'),
						'emu_author' : dict_in.get('emu_author'),
						'dat_filename' : fn_in},
			}

def map_game_choose_list_listitem_dict(category_label,category_count,default_dict,categories_in,game_list_name,type_in=None):
	dict_in = [x for x in categories_in if x.get('label')==category_label]
	if not dict_in:
		dict_in = [default_dict]
		dict_in[0]['label'] = category_label
		dict_in[0]['label2'] = category_label
	current_title = dict_in[0].get('label')
	current_plot = dict_in[0].get('plot')
	if category_count:
		current_title = '%(value)s (%(total)s)'%{'value':dict_in[0].get('label'),'total':category_count}
		current_plot = '%(value)s[CR][CR]Total Games in this Category: %(total)s'%{'value':dict_in[0].get('plot'),'total':category_count}
	return {'values': {'label':current_title,'label2':dict_in[0].get('label')},
			'info':   {'originaltitle':dict_in[0].get('label'),'title':current_title,'plot':current_plot,'trailer':choose_trailer(dict_in[0].get('trailer'),default_dict.get('trailer'))},
			'art':    {'poster':choose_image(dict_in[0].get('thumb'),dict_in[0].get('thumb')),
					   'banner':choose_image(dict_in[0].get('banner'),default_dict.get('banner')),
					   'fanart':choose_image(dict_in[0].get('fanart'),default_dict.get('fanart')),
					   'clearlogo':choose_image(dict_in[0].get('logo'),default_dict.get('logo')),
					   'icon':choose_image(dict_in[0].get('logo'),default_dict.get('logo')),
					   'thumb':choose_image(dict_in[0].get('thumb'),default_dict.get('thumb')),
					   },
			}

def map_game_listitem_dict(dict_in,parent_dict_in,default_dict,game_list_id,clean_titles,naming_convention,date_convention,type_in=None,include_extra_art=True):
	if type_in is None:
		label2 = dict_in.get('@name') #We will use label2 to carry the next route by default
	starts_with = None
	if dict_in.get('description'):
		if dict_in.get('description')[0].isdigit():
			starts_with = '#'
		else:
			starts_with = dict_in.get('description')[0].upper()
	dict_out = {'values': {'label':dict_in.get('description'),'label2':url_quote(label2)}, #Need to url_quote route in case its got wonky chars in it
			'info':   {'title':dict_in.get('description'),
					   'originaltitle':re_game_codes.sub('',re_game_tags.sub('',dict_in.get('description')).strip()).strip(), #Clean name
					   'date':get_date(dict_in.get('releasedate'),dict_in.get('year')),
					   'year':get_date(dict_in.get('releasedate'),dict_in.get('year'),format_in='%Y'),
					   'studio':dict_in.get('studio'),
					   'genre':split_value(dict_in.get('genre')),
					   'showlink':split_value(dict_in.get('groups')),
					   'rating':dict_in.get('rating'),
					   'mpaa':dict_in.get('ESRB'),
					   'plot':dict_in.get('plot'),
					   'tag':get_game_tags(dict_in.get('@name')),
					   'trailer':choose_trailer(dict_in.get('videoid')),
					   # 'path':'plugin://plugin.program.iagl/game/%(game_list_id)s/%(label2)s'%{'game_list_id':game_list_id,'label2':label2},
					   'size':get_game_size(dict_in.get('rom'))},
			'art':    {'poster':choose_image(dict_in.get('boxart1'),dict_in.get('snapshot1'),default_dict.get('thumb')),
					   'banner':choose_image(dict_in.get('banner1'),default_dict.get('banner')),
					   'fanart':choose_image(dict_in.get('fanart1'),default_dict.get('fanart')),
					   #Possibly to be added later if I clean up the xml format
					   # 'extrafanart1':choose_image(dict_in.get('fanart2')),
					   # 'extrafanart2':choose_image(dict_in.get('fanart3')),
					   # 'boxfront':choose_image(dict_in.get('boxfront'),dict_in.get('boxart1')),
					   # 'boxback':choose_image(dict_in.get('boxback'),dict_in.get('boxart2')),
					   # 'cartridge':choose_image(dict_in.get('cartridge'),dict_in.get('boxart3')),
					   # 'snap':choose_image(dict_in.get('snap'),dict_in.get('snapshot2')),
					   # 'title':choose_image(dict_in.get('title'),dict_in.get('snapshot1')),
					   # 'discart':choose_image(dict_in.get('discart'),dict_in.get('boxart3')),
					   'landscape':choose_image(dict_in.get('snapshot1')),
					   'clearlogo':choose_image(dict_in.get('clearlogo1')),
					   'icon':choose_image(dict_in.get('icon'),dict_in.get('clearlogo1')),
					   'thumb':choose_image(dict_in.get('boxart1'),dict_in.get('snapshot1'),default_dict.get('thumb'))},
		'properties': {'route' : next(iter([x for x in [dict_in.get('route'),game_list_id] if x]),game_list_id),  #Look for favorite hyperlink first, then default to current game list id
					   'nplayers':dict_in.get('nplayers'),
					   'perspective':dict_in.get('perspective'),
					   'description':dict_in.get('description'), #Need to carry a clean version of this for favorites if necessary
					   'starts_with':starts_with,
					   'platform_name':parent_dict_in.get('emu_name'),
					   'platform_description':parent_dict_in.get('emu_description'),
					   'platform_category':parent_dict_in.get('emu_category'),
					   'platform_banner':choose_image(parent_dict_in.get('emu_banner')),
					   'platform_fanart':choose_image(parent_dict_in.get('emu_fanart')),
					   'platform_clearlogo':choose_image(parent_dict_in.get('emu_logo')),
					   'platform_thumb':choose_image(parent_dict_in.get('emu_thumb')),
					   'platform_plot':parent_dict_in.get('emu_comment'),
					   'emu_command':dict_in.get('emu_command'),
					   'emu_baseurl':parent_dict_in.get('emu_baseurl'),
					   'emu_launcher':parent_dict_in.get('emu_launcher'),
					   'emu_ext_launch_cmd':next(iter([x for x in [dict_in.get('rom_override_cmd'),parent_dict_in.get('emu_ext_launch_cmd')] if x]),'none'), #Look for override commands first, then default to game list settings
					   'emu_default_addon':next(iter([x for x in [dict_in.get('rom_override_cmd'),parent_dict_in.get('emu_default_addon')] if x]),'default'),
					   'emu_downloadpath':next(iter([x for x in [dict_in.get('rom_override_downloadpath'),parent_dict_in.get('emu_downloadpath')] if x]),'default'),
					   'emu_postdlaction':next(iter([x for x in [dict_in.get('rom_override_postdl'),parent_dict_in.get('emu_postdlaction')] if x]),'none'),
					   'rom' : json.dumps(dict_in.get('rom')),
					   },
			}
	if include_extra_art:
		for kk in zip(['game_boxarts','game_banners','game_snapshots','game_logos','game_fanarts'],['boxart','banner','snapshot','clearlogo','fanart']):
			dict_out['properties'][kk[0]] = json.dumps([x for x in [dict_in.get('%(kk)s%(nn)s'%{'kk':kk[1],'nn':y}) for y in range(1,MAX_ART)] if x])
	else:
		for kk in zip(['game_boxarts','game_banners','game_snapshots','game_logos','game_fanarts'],['thumb','banner','landscape','clearlogo','fanart']):
			dict_out['properties'][kk[0]] = json.dumps([dict_out.get('art').get(kk[1])])

	if dict_out.get('info').get('date') is None: #Hack because Kodi spams the logs if date is None
		del dict_out['info']['date']
	if naming_convention != '%(title)s':
		if clean_titles:
			dict_out['values']['label'] = naming_convention%{'date':get_date(dict_in.get('releasedate'),dict_in.get('year'),format_in=date_convention),'genre':dict_in.get('genre'),'nplayers':dict_in.get('nplayers'),'size':bytes_to_string_size(dict_out.get('info').get('size')),'tag':combine_value(dict_out.get('info').get('tag')),'title':dict_out.get('info').get('originaltitle')}
		else:
			dict_out['values']['label'] = naming_convention%{'date':get_date(dict_in.get('releasedate'),dict_in.get('year'),format_in=date_convention),'genre':dict_in.get('genre'),'nplayers':dict_in.get('nplayers'),'size':bytes_to_string_size(dict_out.get('info').get('size')),'tag':combine_value(dict_out.get('info').get('tag')),'title':dict_in.get('description')}
		dict_out['values']['label'] = dict_out['values']['label'].replace('| None ','').replace('| None','').strip()
	else:
		if clean_titles:
			dict_out['values']['label'] = dict_out['info']['originaltitle']
	dict_out['info']['title'] = dict_out['values']['label'] #Estuary seems to use title now as the listitem label, so updating the title here is necessary
	return dict_out

def map_retroplayer_listitem_dict(dict_in,launch_dict_in): #https://codedocs.xyz/xbmc/xbmc/group__python__xbmcgui__listitem.html
	dict_out = {'values': {'label':dict_in.get('values').get('label'),'label2':dict_in.get('values').get('label2')},
			'info':   {'title':dict_in.get('info').get('originaltitle'),
					   'platform':dict_in.get('properties').get('platform_description'),
					   'genre':dict_in.get('info').get('genre'),
					   'publisher':dict_in.get('info').get('studio'),
					   'overview':dict_in.get('info').get('plot'),
					   'year':dict_in.get('info').get('year'),
					   'gameclient':next(iter([x for x in [launch_dict_in.get('default_addon')] if x and x!='none']),None)},
			'art':    {'poster':dict_in.get('art').get('poster'),
					   'banner':dict_in.get('art').get('banner'),
					   'fanart':dict_in.get('art').get('fanart'),
					   'landscape':dict_in.get('art').get('landscape'),
					   'clearlogo':dict_in.get('art').get('clearlogo'),
					   'icon':dict_in.get('art').get('icon'),
					   'thumb':dict_in.get('art').get('thumb')},
			}
	return dict_out

def map_wizard_report_listitem_dict(dict_in,media_type='video'):
	if isinstance(dict_in,dict):
		lis = list()
		for ii,dd in enumerate(dict_in.get('label')):
			li = xbmcgui.ListItem(label=dd,offscreen=True)
			if dict_in.get('info'):
				li.setInfo(media_type,dict_in.get('info')[ii])
			if dict_in.get('art'):
				li.setArt(dict_in.get('art')[ii])
			lis.append(li)
		return lis
	else:
		return None

def get_game_stat_set(game_stats_in=None,type_in=None):
	if isinstance(game_stats_in,list) and type_in:
		stats_out = sorted(set(flatten_list([x[type_in]['all'] for x in game_stats_in])))
		return stats_out
	else:
		return []

def get_history_listitem(media_type='video'):
	li_dict = {'info':{'genre':loc_str(30600),'plot':loc_str(30601)},
	'art':{'icon':'special://home/addons/plugin.program.iagl/resources/skins/Default/media/icon.png',
	'thumb':'special://home/addons/plugin.program.iagl/resources/skins/Default/media/last_played.jpg',
	'poster':'special://home/addons/plugin.program.iagl/resources/skins/Default/media/last_played.jpg',
	'banner':'special://home/addons/plugin.program.iagl/resources/skins/Default/media/last_played_banner.jpg',
	'fanart':'special://home/addons/plugin.program.iagl/resources/skins/Default/media/fanart.jpg'}}
	li = xbmcgui.ListItem(label=loc_str(30599),offscreen=True)
	li.setInfo(media_type,li_dict.get('info'))
	li.setArt(li_dict.get('art'))
	li.setProperties({'SpecialSort':'bottom'})
	return li

def get_next_page_listitem(current_page,page_count,next_page,total_items,media_type='video'):
	li = xbmcgui.ListItem(label=loc_str(30602),offscreen=True)
	li.setInfo(media_type,{'plot':loc_str(30603)%{'current_page':current_page,'page_count':page_count,'next_page':next_page,'total_items':total_items}})
	li.setArt({'icon':'special://home/addons/plugin.program.iagl/resources/skins/Default/media/next.png','thumb':'special://home/addons/plugin.program.iagl/resources/skins/Default/media/next.png'})
	li.setProperties({'SpecialSort':'bottom'})
	return li

def get_blank_favorites_listitem(media_type='video'):
	li = xbmcgui.ListItem(label=loc_str(30439),offscreen=True)
	li.setArt({'icon':'special://home/addons/plugin.program.iagl/resources/skins/Default/media/favorites_logo.png',
				'thumb':'special://home/addons/plugin.program.iagl/resources/skins/Default/media/favorites.png',
				'poster':'special://home/addons/plugin.program.iagl/resources/skins/Default/media/favorites.png',
				'banner':'special://home/addons/plugin.program.iagl/resources/skins/Default/media/favorites_banner.png',
				'fanart':'special://home/addons/plugin.program.iagl/resources/skins/Default/media/fanart.jpg'})
	return li


def get_netplay_listitem(media_type='video'):
	li_dict = {'info':{'genre':loc_str(30004),'plot':loc_str(30598)},
	'art':{'icon':'special://home/addons/plugin.program.iagl/resources/skins/Default/media/netplay_logo.png',
	'thumb':'special://home/addons/plugin.program.iagl/resources/skins/Default/media/netplay_box.jpg',
	'poster':'special://home/addons/plugin.program.iagl/resources/skins/Default/media/netplay_box.jpg',
	'banner':'special://home/addons/plugin.program.iagl/resources/skins/Default/media/netplay_banner.jpg',
	'fanart':'special://home/addons/plugin.program.iagl/resources/skins/Default/media/fanart.jpg'}}
	li = xbmcgui.ListItem(label=loc_str(30004),offscreen=True)
	li.setInfo(media_type,li_dict.get('info'))
	li.setArt(li_dict.get('art'))
	li.setProperties({'SpecialSort':'bottom'})
	return li

def get_database_listitem(dict_in,media_type='video'):
	if isinstance(dict_in,dict):
		li = xbmcgui.ListItem(label=dict_in.get('values').get('label'),label2=dict_in.get('values').get('label2'),offscreen=True)
		li.setInfo(media_type,dict_in.get('info'))
		li.setArt(dict_in.get('art'))
		li.setProperties(dict_in.get('properties'))
		return li
	else:
		return None

def get_game_list_listitem(dict_in,filter_in=None,media_type='video'):
	li=None
	if dict_in.get('properties').get('emu_visibility') != 'hidden' and (filter_in is None or (all([filter_in.get('info').get(kk) in dict_in.get('info').get(kk) if dict_in.get('info').get(kk) else False for kk in filter_in.get('info').keys()]) and all([filter_in.get('properties').get(kk) in dict_in.get('properties').get(kk) if dict_in.get('properties').get(kk) else False for kk in filter_in.get('properties').keys()]))):
		li = xbmcgui.ListItem(label=dict_in.get('values').get('label'),label2=dict_in.get('values').get('label2'),offscreen=True)
		li.setInfo(media_type,dict_in.get('info'))
		li.setArt(dict_in.get('art'))
	return li

def get_retroplayer_item_and_listitem(dict_in,launch_file,media_type='game'):
	# launch_item = None
	launch_li = None
	# if launch_file:
	# 	launch_item = str(launch_file)
	if launch_file and dict_in:
		launch_li = xbmcgui.ListItem(label=dict_in.get('values').get('label'),label2=dict_in.get('values').get('label2'),offscreen=True)
		launch_li.setInfo(media_type,dict_in.get('info'))
		launch_li.setArt(dict_in.get('art'))
		launch_li.setPath(path=str(launch_file))
	return launch_li

def get_game_choose_list_listitem(dict_in,filter_in=None,media_type='video'):
	if isinstance(dict_in,dict):
		li = xbmcgui.ListItem(label=dict_in.get('values').get('label'),label2=dict_in.get('values').get('label2'),offscreen=True)
		li.setInfo(media_type,dict_in.get('info'))
		li.setArt(dict_in.get('art'))
		li.setProperties(dict_in.get('properties'))
		return li
	else:
		return None

def update_listitem_title(li_in,update_item,media_type='video'):
	if update_item:
		li_in.setInfo(media_type,{'title':'%(emu_name)s - %(label)s'%{'emu_name':li_in.getProperty('platform_description'),'label':li_in.getLabel()}})
		li_in.setLabel('%(emu_name)s - %(label)s'%{'emu_name':li_in.getProperty('platform_description'),'label':li_in.getLabel()})
		return li_in
	else:
		return li_in

def game_filter(dict_in,filter_in):
	include = list()
	if filter_in is not None: #Game must match all filter query props
		for kk in ['info','properties']:
			for k,v in filter_in.get(kk).items():
				if isinstance(v,str):
					if dict_in.get(kk).get(k) is None and v=='Unknown':
						include.append(True)
					elif isinstance(dict_in.get(kk).get(k),list) and v!='Unknown':
						if v in dict_in.get(kk).get(k):
							include.append(True)
						else:
							include.append(False)
					elif isinstance(dict_in.get(kk).get(k),str) and v!='Unknown':
						if v==dict_in.get(kk).get(k):
							include.append(True)
						else:
							include.append(False)
					else:
						include.append(False)
				if isinstance(v,list):
					if dict_in.get(kk).get(k) is None and 'Unknown' in v:
						include.append(True)
					elif isinstance(dict_in.get(kk).get(k),list) and 'Unknown' not in v:
						if any([vv in dict_in.get(kk).get(k) for vv in v]):
							include.append(True)
						else:
							include.append(False)
					elif isinstance(dict_in.get(kk).get(k),str) and 'Unknown' not in v:
						if any([vv==dict_in.get(kk).get(k) for vv in v]):
							include.append(True)
						else:
							include.append(False)
					else:
						include.append(False)
				if isinstance(v,re.Pattern):
					if isinstance(dict_in.get(kk).get(k),str):
						if v.findall(dict_in.get(kk).get(k)):
							include.append(True)
						else:
							include.append(False)
					else:
						include.append(False)
	else:
		include.append(True)
	return include

def url_quote_query(query_in):
	if isinstance(query_in,dict):
		return url_quote(json.dumps(query_in))
	else:
		return None

def get_game_listitem(dict_in,filter_in,media_type='video'):
	li=None
	include = game_filter(dict_in,filter_in)
	# 	zachs_debug('Filter')
	# 	zachs_debug(filter_in)
	# 	zachs_debug('Dict')
	# 	zachs_debug(dict_in)
	# 	zachs_debug('Unknowns')
	# 	zachs_debug([True if not dict_in.get('info').get(k) else False for k,v in filter_in.get('info').items() if v=='Unknown'])
	# 	zachs_debug([True if not dict_in.get('properties').get(k) else False for k,v in filter_in.get('properties').items() if v=='Unknown'])
	# 	zachs_debug('Knowns')
	# 	zachs_debug([v in dict_in.get('info').get(k) if (v is not None and dict_in.get('info').get(k) is not None) else False for k,v in filter_in.get('info').items() if v!='Unknown'])
	# 	zachs_debug([v in dict_in.get('info').get(k) if v is not None else False for k,v in filter_in.get('info').items() if v!='Unknown' and dict_in.get('info') is not None and dict_in.get('info').get(k) is not None])
	# 	zachs_debug([v in dict_in.get('properties').get(k) if (v is not None and dict_in.get('properties').get(k) is not None) else False for k,v in filter_in.get('properties').items() if v!='Unknown'])
	# 	zachs_debug([v in dict_in.get('properties').get(k) if v is not None else False for k,v in filter_in.get('properties').items() if v!='Uknown' and dict_in.get('properties') is not None and dict_in.get('properties').get(k) is not None])
	# if filter_in is None or (all([v in dict_in.get('info').get(k) if (v is not None and dict_in.get('info').get(k) is not None) else False for k,v in filter_in.get('info').items() if v!='Unknown']) and all([v in dict_in.get('properties').get(k) if (v is not None and dict_in.get('properties').get(k) is not None) else False for k,v in filter_in.get('properties').items() if v!='Unknown']) and all([True if not dict_in.get('info').get(k) else False for k,v in filter_in.get('info').items() if v=='Unknown']) and all([True if not dict_in.get('properties').get(k) else False for k,v in filter_in.get('properties').items() if v=='Unknown'])):
	if all(include):
		li = xbmcgui.ListItem(label=dict_in.get('values').get('label'),label2=dict_in.get('values').get('label2'),offscreen=True)
		li.setInfo(media_type,dict_in.get('info'))
		li.setArt(dict_in.get('art'))
		li.setProperties(dict_in.get('properties'))
	return li

def choose_image(*args):
	image = next(iter([x for x in args if x and isinstance(x,str)]), None)
	if image is not None and 'http' not in image and 'special:' not in image:
		return 'https://i.imgur.com/%(image)s'%{'image':image}
	else:
		return image

def clean_image_entry(value_in):
	if value_in and isinstance(value_in,str):
		valid_image_extensions = ['.png','.jpg','.jpeg','.gif','.tiff','.tif','.bmp','.ico','.pcx','.webp','.tga'] #https://kodi.wiki/view/Features_and_supported_formats
		if 'http' in value_in.lower():
			value_out = value_in
			if 'imgur.com' in value_in.lower():
				value_out = value_in.split('/')[-1]
			if any([x in value_out.lower() for x in valid_image_extensions]):
				return value_out
		elif 'special:' in value_in.lower() and check_if_file_exists(value_in) and any([x in value_in.lower() for x in valid_image_extensions]):
			return value_in
		else:
			xbmc.log(msg='IAGL:  The entry for a new art asset does not appear to be a valid web or local image file', level=xbmc.LOGERROR)
			return None
	else:
		return None

def choose_trailer(*args):
	vid = next(iter([x for x in args if x and isinstance(x,str)]), None)
	if vid is not None and 'http' not in vid:
		return 'plugin://plugin.video.youtube/play/?video_id=%(vid)s'%{'vid':vid}
	else:
		return vid

def clean_trailer_entry(value_in):
	if value_in and isinstance(value_in,str):
		valid_video_extensions = ['.mpg','.mp4','.m4v','.mpeg','.m4p','.mov','.avi','.wmv','.webm','.mp2','.mpe','.mpv','.ogg','.qt','.flv','.swf','.avchd']
		if 'youtube' in value_in.lower():
			return value_in.split('=')[-1]
		elif 'special:' in value_in.lower() and check_if_file_exists(value_in) and any([x in value_in.lower() for x in valid_video_extensions]):
			return value_in
		else:
			xbmc.log(msg='IAGL:  The entry for a new trailer asset does not appear to be a valid web or local video file', level=xbmc.LOGERROR)
			return None
	else:
		return None

def get_date(*args,format_in='%d.%m.%Y'):
	ignore_list = ['?','??','???','????','19??','197?','198?','199?','200?','201?','1980?','1990?','1981?','1987?','1996?'] #Known bad dates to speed things up, will try and remove these from the xmls in the future
	date_in = next(iter([x.strip() for x in args if x and isinstance(x,str) and x not in ignore_list]), None)
	if date_in:
		try:
			return date_parser.parse(date_in).strftime(format_in)
		except Exception as exc:
			xbmc.log(msg='IAGL:  Unable to parse date %(date_in)s.  Exception %(exc)s' % {'date_in': date_in, 'exc': exc}, level=xbmc.LOGDEBUG)
			return None
	else:
		return None

def get_xml_header(file_in,default_dir=None):
	header_out = get_calculated_header_values(get_xml_header_path_et_fromstring(file_in),filename_in=file_in,default_dir=default_dir) #Try getting xml header from path (fast)
	# header_out = get_xml_header_path_xmltodict(file_in) #Try getting xml header from path (fast)
	if header_out:
		return header_out
	else:
		return get_calculated_header_values(get_xml_header_xbmcvfs_et_fromstring(str(file_in)),filename_in=file_in,default_dir=default_dir) #If it fails, use xbmcvfs (slower)
		# return get_xml_header_xbmcvfs_xmltodict(str(file_in)) #If it fails, use xbmcvfs (slower)

def get_xml_header_path_et_fromstring(file_in):
	if check_if_file_exists(file_in):
		with file_in.open(mode='rb') as f:
			byte_string = f.read(HEADER_SIZE)
		if b'</header>' in byte_string:
			try:
				xml_etree = ET.fromstring(byte_string.split(b'</header>')[0]+b'</header></datafile>')
				return dict(zip([y.tag for y in [list(x) for x in xml_etree.iter('header')][0]],[y.text for y in [list(x) for x in xml_etree.iter('header')][0]]))
				# return etree_to_dict(ET.fromstring(byte_string.split(b'</header>')[0]+b'</header></datafile>')).get('datafile').get('header')
			except Exception as exc:
				xbmc.log(msg='IAGL:  Error reading header for %(value_in)s.  Exception %(exc)s' % {'value_in': file_in.name, 'exc': exc}, level=xbmc.LOGERROR)
				return None
		else:
			xbmc.log(msg='IAGL:  End of header not found for %(value_in)s' % {'value_in': file_in.name, 'exc': exc}, level=xbmc.LOGERROR)
			return None
	else:
		xbmc.log(msg='IAGL:  Error xml file %(value_in)s does not exist' % {'value_in': file_in.name}, level=xbmc.LOGERROR)
		return None

def get_calculated_header_values(dict_in,filename_in=None,default_dir=None):
	dict_in['download_source'] = 'Unknown'
	dict_in['emu_downloadpath_resolved'] = default_dir
	dict_in['download_destination'] = 'Cache'
	if filename_in:
		dict_in['game_list_id'] = os.path.splitext(os.path.split(filename_in)[-1])[0]
	else:
		dict_in['game_list_id'] = None
	if all([x in dict_in.get('emu_baseurl') for x in ['http','archive.org']]):
		dict_in['download_source'] = 'Archive.org'
	elif any([x in dict_in.get('emu_baseurl') for x in ['http:','https:']]):
		dict_in['download_source'] = dict_in.get('emu_baseurl')
	elif any([x in dict_in.get('emu_baseurl') for x in ['smb:','nfs:']]):
		dict_in['download_source'] = 'Local Network Source'
	elif any([x in dict_in.get('emu_baseurl') for x in ['special:','library:']]):
		dict_in['download_source'] = 'Kodi Library Source'
	elif Path(dict_in.get('emu_baseurl')).exists():
		dict_in['download_source'] = 'Local File Source'
	if dict_in.get('emu_downloadpath') != 'default' and check_if_dir_exists(Path(dict_in.get('emu_downloadpath'))):
		dict_in['emu_downloadpath_resolved'] = Path(xbmcvfs.translatePath(dict_in.get('emu_downloadpath'))).expanduser()
		dict_in['download_destination'] = 'Local File Destination'
	elif dict_in.get('emu_downloadpath') != 'default' and check_if_dir_exists(str(dict_in.get('emu_downloadpath'))):
		dict_in['emu_downloadpath_resolved'] = xbmcvfs.translatePath(dict_in.get('emu_downloadpath'))
		dict_in['download_destination'] = 'Kodi Library Destination'
	return dict_in

# def get_xml_header_path_xmltodict(file_in):
# 	if file_in.exists():
# 		with file_in.open(mode='rb') as f:
# 			byte_string = f.read(HEADER_SIZE)
# 		if b'</header>' in byte_string:
# 			try:
# 				return xmltodict.parse(byte_string.split(b'</header>')[0]+b'</header></datafile>').get('datafile').get('header')
# 			except Exception as exc:
# 				xbmc.log(msg='IAGL:  Error reading header for %(value_in)s.  Exception %(exc)s' % {'value_in': file_in.name, 'exc': exc}, level=xbmc.LOGERROR)
# 				return None
# 		else:
# 			xbmc.log(msg='IAGL:  End of header not found for %(value_in)s' % {'value_in': file_in.name, 'exc': exc}, level=xbmc.LOGERROR)
# 			return None
# 	else:
# 		xbmc.log(msg='IAGL:  Error xml file %(value_in)s does not exist' % {'value_in': file_in.name}, level=xbmc.LOGERROR)
# 		return None

def get_xml_header_xbmcvfs_et_fromstring(file_in):
	if check_if_file_exists(file_in):
		with xbmcvfs.File(str(file_in)) as fi:
			byte_string = bytes(fi.readBytes(HEADER_SIZE))
		if b'</header>' in byte_string:
			try:
				xml_etree = ET.fromstring(byte_string.split(b'</header>')[0]+b'</header></datafile>')
				return dict(zip([y.tag for y in [list(x) for x in xml_etree.iter('header')][0]],[y.text for y in [list(x) for x in xml_etree.iter('header')][0]]))
				# return etree_to_dict(ET.fromstring(byte_string.split(b'</header>')[0]+b'</header></datafile>')).get('datafile').get('header')
			except Exception as exc:
				xbmc.log(msg='IAGL:  Error reading header for %(value_in)s.  Exception %(exc)s' % {'value_in': file_in, 'exc': exc}, level=xbmc.LOGERROR)
				return None
		else:
			xbmc.log(msg='IAGL:  End of header not found for %(value_in)s' % {'value_in': file_in, 'exc': exc}, level=xbmc.LOGERROR)
			return None
	else:
		xbmc.log(msg='IAGL:  Error xml file %(value_in)s does not exist' % {'value_in': file_in}, level=xbmc.LOGERROR)
		return None

# def get_xml_header_xbmcvfs_xmltodict(file_in):
# 	if xbmcvfs.exists(file_in):
# 		with xbmcvfs.File(file_in) as fi:
# 			byte_string = bytes(fi.readBytes(HEADER_SIZE))
# 		if b'</header>' in byte_string:
# 			try:
# 				return xmltodict.parse(byte_string.split(b'</header>')[0]+b'</header></datafile>').get('datafile').get('header')
# 			except Exception as exc:
# 				xbmc.log(msg='IAGL:  Error reading header for %(value_in)s.  Exception %(exc)s' % {'value_in': file_in, 'exc': exc}, level=xbmc.LOGERROR)
# 				return None
# 		else:
# 			xbmc.log(msg='IAGL:  End of header not found for %(value_in)s' % {'value_in': file_in, 'exc': exc}, level=xbmc.LOGERROR)
# 			return None
# 	else:
# 		xbmc.log(msg='IAGL:  Error xml file %(value_in)s does not exist' % {'value_in': file_in}, level=xbmc.LOGERROR)
# 		return None

def dict_to_xml_header(dict_in):
	xml_header_out = '<?xml version="1.0" encoding="UTF-8"?>\n<datafile>\n\t<header>\n\t\t<emu_name>%(emu_name)s</emu_name>\n\t\t<emu_description>%(emu_description)s</emu_description>\n\t\t<emu_category>%(emu_category)s</emu_category>\n\t\t<emu_version>%(emu_version)s</emu_version>\n\t\t<emu_date>%(emu_date)s</emu_date>\n\t\t<emu_author>%(emu_author)s</emu_author>\n\t\t<emu_visibility>%(emu_visibility)s</emu_visibility>\n\t\t<emu_homepage>%(emu_homepage)s</emu_homepage>\n\t\t<emu_baseurl>%(emu_baseurl)s</emu_baseurl>\n\t\t<emu_launcher>%(emu_launcher)s</emu_launcher>\n\t\t<emu_default_addon>%(emu_default_addon)s</emu_default_addon>\n\t\t<emu_ext_launch_cmd>%(emu_ext_launch_cmd)s</emu_ext_launch_cmd>\n\t\t<emu_downloadpath>%(emu_downloadpath)s</emu_downloadpath>\n\t\t<emu_postdlaction>%(emu_postdlaction)s</emu_postdlaction>\n\t\t<emu_comment>%(emu_comment)s</emu_comment>\n\t\t<emu_thumb>%(emu_thumb)s</emu_thumb>\n\t\t<emu_banner>%(emu_banner)s</emu_banner>\n\t\t<emu_fanart>%(emu_fanart)s</emu_fanart>\n\t\t<emu_logo>%(emu_logo)s</emu_logo>\n\t\t<emu_trailer>%(emu_trailer)s</emu_trailer>\n\t</header>'%{'emu_name':dict_in.get('emu_name'),'emu_description':dict_in.get('emu_description'),'emu_category':dict_in.get('emu_category'),'emu_version':dict_in.get('emu_version'),'emu_date':dict_in.get('emu_date'),'emu_author':dict_in.get('emu_author'),'emu_visibility':dict_in.get('emu_visibility'),'emu_homepage':dict_in.get('emu_homepage'),'emu_baseurl':dict_in.get('emu_baseurl'),'emu_launcher':dict_in.get('emu_launcher'),'emu_default_addon':dict_in.get('emu_default_addon'),'emu_ext_launch_cmd':dict_in.get('emu_ext_launch_cmd'),'emu_downloadpath':dict_in.get('emu_downloadpath'),'emu_postdlaction':dict_in.get('emu_postdlaction'),'emu_comment':dict_in.get('emu_comment'),'emu_thumb':dict_in.get('emu_thumb'),'emu_banner':dict_in.get('emu_banner'),'emu_fanart':dict_in.get('emu_fanart'),'emu_logo':dict_in.get('emu_logo'),'emu_trailer':dict_in.get('emu_trailer')}
	# if '%' in xml_header_out:
	if re.findall('\%\(.*?\)s',xml_header_out):
		xbmc.log(msg='IAGL:  The xml header was not well formed.  Current value %(value_in)s' % {'value_in': xml_header_out}, level=xbmc.LOGERROR)
		xml_header_out = None
	return xml_header_out

def update_xml_file(file_in,dict_in):
	success = False
	if file_in.is_file() and isinstance(dict_in,dict):
		new_file_text = '%(new_header)s%(file_data)s'%{'new_header':dict_to_xml_header(dict_in),'file_data':file_in.read_text(encoding=TEXT_ENCODING).split('</header>')[-1]}
		if all([x in new_file_text for x in ['<datafile>','<header>','</header>','</datafile>']]): #Verify all the required keys are in the file
			try:
				file_in.write_text(new_file_text,encoding=TEXT_ENCODING)
				success = True
			except Exception as exc:
				xbmc.log(msg='IAGL:  Error writing xml file %(value_in)s.  Exception %(exc)s' % {'value_in': file_in, 'exc': exc}, level=xbmc.LOGERROR)
		else:
			xbmc.log(msg='IAGL:  The xml file cannot be written because is was not well formed.  Current file %(file_in)s' % {'file_in': file_in}, level=xbmc.LOGERROR)
	else:
		xbmc.log(msg='IAGL:  The xml edit request was not well formed.  Current file %(file_in)s' % {'file_in': file_in}, level=xbmc.LOGERROR)
	return success

def get_ra_cmds(default_cmd,ra_cfg_path,ra_app_path):
	if isinstance(default_cmd,list) and len(default_cmd)==1 and check_if_file_exists(ra_cfg_path) and check_if_file_exists(ra_app_path):
		ra_cores = dict()
		ra_cfg = get_ra_libretro_config(ra_cfg_path,ra_app_path)
		if ra_cfg.get('libretro_directory') and ra_cfg.get('libretro_info_path'):
			xbmc.log(msg='IAGL:  The libretro directory is identified as %(libretro_directory)s and the core info path is %(libretro_info_path)s' % {'libretro_directory':ra_cfg.get('libretro_directory'),'libretro_info_path': ra_cfg.get('libretro_info_path')}, level=xbmc.LOGDEBUG)
			ra_cores['cores'] = sorted([x for x in ra_cfg.get('libretro_directory').glob('**/*') if x.is_file() and x.suffix in ['.dylib','.dll','.so']])
			info_files = [y for y in ra_cfg.get('libretro_info_path').glob('*.info') if y.is_file()]
			ra_cores['name'] = ['RetroArch %(core_name)s'%{'core_name':x[0].get('display_name')} if x[0].get('display_name') else 'RetroArch %(core_name)s'%{'core_name':x[1].stem} for x in zip([get_ra_info(x.stem,info_files) for x in ra_cores.get('cores')],ra_cores['cores'])]
			return [define_ra_cmd(x[0],x[1],default_cmd[0].copy(),ra_app_path) for x in zip(ra_cores['name'],ra_cores['cores'])]
		else:
			xbmc.log(msg='IAGL:  The libretro directory and info file path parameters are not present in the config file %(file_in)s' % {'file_in': ra_cfg_path}, level=xbmc.LOGERROR)
			return None
	else:
		return None

def get_game_list_stats(games):
	stats_out = dict()
	if games:
		stats_out['alphabetical'] = dict()
		stats_out['genres'] = dict()
		stats_out['years'] = dict()
		stats_out['players'] = dict()
		stats_out['studio'] = dict()
		stats_out['tag'] = dict()
		stats_out['groups'] = dict()
		stats_out['alphabetical']['all'] = ['#']+[chr(x) for x in range(ord('A'), ord('Z') + 1)]
		stats_out['genres']['all'] = sorted(set(flatten_list([x.get('info').get('genre') for x in games if x.get('info').get('genre')])))
		stats_out['years']['all'] = sorted(set([x.get('info').get('year') for x in games if x.get('info').get('year')]))
		stats_out['players']['all'] = sorted(set([x.get('properties').get('nplayers') for x in games if x.get('properties').get('nplayers')]))
		stats_out['studio']['all'] = sorted(set([x.get('info').get('studio') for x in games if x.get('info').get('studio')]))
		stats_out['tag']['all'] = sorted(set(flatten_list([x.get('info').get('tag') for x in games if x.get('info').get('tag')])))
		stats_out['groups']['all'] = sorted(set(flatten_list([x.get('info').get('showlink') for x in games if x.get('info').get('showlink')])))
		if stats_out['alphabetical']['all']:
			# stats_out['alphabetical']['count'] = [sum([y.get('values').get('label').upper().startswith(x) for y in games]) for x in stats_out['alphabetical']['all']]
			# stats_out['alphabetical']['count'][0] = sum([not y.get('values').get('label')[0].isalpha() for y in games if isinstance(y.get('values').get('label'),str) and len()]) #Recalc the numerical stats
			stats_out['alphabetical']['count'] = [sum([y.get('properties').get('starts_with').startswith(x) for y in games if y.get('properties').get('starts_with')]) for x in stats_out['alphabetical']['all']]
			#Remove 0 count alphabetical
			stats_out['alphabetical']['all'] = [x[0] for x in zip(stats_out['alphabetical']['all'],stats_out['alphabetical']['count']) if x[1]>0]
			stats_out['alphabetical']['count'] = [x for x in stats_out['alphabetical']['count'] if x>0]
		if stats_out['genres']['all']:
			stats_out['genres']['count'] = [sum([x in y.get('info').get('genre') if y.get('info').get('genre') else False for y in games]) for x in stats_out['genres']['all']]
		if stats_out['years']['all']:
			stats_out['years']['count'] = [sum([x in y.get('info').get('year') if y.get('info').get('year') else False for y in games]) for x in stats_out['years']['all']]
		if stats_out['players']['all']:
			stats_out['players']['count'] = [sum([x in y.get('properties').get('nplayers') if y.get('properties').get('nplayers') else False for y in games]) for x in stats_out['players']['all']]
		if stats_out['studio']['all']:
			stats_out['studio']['count'] = [sum([x in y.get('info').get('studio') if y.get('info').get('studio') else False for y in games]) for x in stats_out['studio']['all']]
		if stats_out['tag']['all']:
			stats_out['tag']['count'] = [sum([x in y.get('info').get('tag') if y.get('info').get('tag') else False for y in games]) for x in stats_out['tag']['all']]
		if stats_out['groups']['all']:
			stats_out['groups']['count'] = [sum([x in y.get('info').get('showlink') if y.get('info').get('showlink') else False for y in games]) for x in stats_out['groups']['all']]
		#Add uncategorized / unset counts
		unknowns = dict()
		unknowns['genres'] = sum([not y.get('info').get('genre') for y in games]) #Uncategorized, unset count
		unknowns['years'] = sum([not y.get('info').get('year') for y in games]) #Uncategorized, unset count
		unknowns['players'] = sum([not y.get('properties').get('nplayers') for y in games]) #Uncategorized, unset count
		unknowns['studio'] = sum([not y.get('info').get('studio') for y in games]) #Uncategorized, unset count
		unknowns['tag'] = sum([not y.get('info').get('tag') for y in games]) #Uncategorized, unset count
		unknowns['groups'] = sum([not y.get('info').get('showlink') for y in games]) #Uncategorized, unset count
		for kk in ['genres','years','players','studio','tag','groups']:
			if unknowns[kk]>0:
				if stats_out[kk].get('all'):
					stats_out[kk]['all'].append('Unknown')
					stats_out[kk]['count'].append(unknowns[kk])
				else:
					stats_out[kk]['all'] = ['Unknown']
					stats_out[kk]['count'] = [unknowns[kk]]
		#Add overall stats, totals for each grouping and total games in the list
		stats_out['overall'] = dict()
		stats_out['overall']['count'] = len(games)
		stats_out['overall']['alphabetical'] = 0
		stats_out['overall']['genres'] = 0
		stats_out['overall']['years'] = 0
		stats_out['overall']['players'] = 0
		stats_out['overall']['studio'] = 0
		stats_out['overall']['tag'] = 0
		stats_out['overall']['groups'] = 0
		if stats_out['alphabetical'].get('all'):
			stats_out['overall']['alphabetical'] = len(stats_out['alphabetical']['all'])
		if stats_out['genres'].get('all'):
			stats_out['overall']['genres'] = len(stats_out['genres']['all'])
		if stats_out['years'].get('all'):
			stats_out['overall']['years'] = len(stats_out['years']['all'])
		if stats_out['players'].get('all'):
			stats_out['overall']['players'] = len(stats_out['players']['all'])
		if stats_out['studio'].get('all'):
			stats_out['overall']['studio'] = len(stats_out['studio']['all'])
		if stats_out['tag'].get('all'):
			stats_out['overall']['tag'] = len(stats_out['tag']['all'])
		if stats_out['groups'].get('all'):
			stats_out['overall']['groups'] = len(stats_out['groups']['all'])
	return stats_out

def add_game_to_history(dict_in,file_in,max_history):
	success = False
	if isinstance(dict_in,dict):
		dict_in['info']['lastplayed'] = time.strftime('%Y-%m-%d %H:%M:%S') #lastplayed	string (Y-m-d h:m:s = 2009-04-05 23:16:04)
		if check_if_file_exists(file_in):
			with xbmcvfs.File(str(file_in),'rb') as fi:
				history = json.load(fi)
			prev_history = [x for x in history[0] if not (x.get('values').get('label2') == dict_in.get('values').get('label2') and x.get('properties').get('route') == dict_in.get('properties').get('route'))]
			if len(prev_history) == len(history[0]): #Game was not previously in history
				with xbmcvfs.File(str(file_in),'wb') as fi:
					json.dump([[x for x in [dict_in]+history[0]][0:max_history],get_game_list_stats([x for x in [dict_in]+history[0]][0:max_history])],fi)
					# [games_in,stats_in]
					xbmc.log(msg='IAGL:  Added %(game)s to history file' % {'game': dict_in.get('info').get('originaltitle')}, level=xbmc.LOGDEBUG)
				with xbmcvfs.File(str(file_in).replace('.json','_stats.json'),'wb') as fi:
					json.dump(get_game_list_stats([x for x in [dict_in]+history[0]][0:max_history]),fi)
					success = True
			else: #Game was already in history, so remove old instance and replace it with new instance
				with xbmcvfs.File(str(file_in),'wb') as fi:
					json.dump([[x for x in [dict_in]+prev_history][0:max_history],get_game_list_stats([x for x in [dict_in]+prev_history][0:max_history])],fi)
					xbmc.log(msg='IAGL:  Updated %(game)s to last played game in history file' % {'game': dict_in.get('info').get('originaltitle')}, level=xbmc.LOGDEBUG)
				with xbmcvfs.File(str(file_in).replace('.json','_stats.json'),'wb') as fi:
					json.dump(get_game_list_stats([x for x in [dict_in]+prev_history][0:max_history]),fi)
					success = True
		else:
			with xbmcvfs.File(str(file_in),'wb') as fi:
				json.dump([[dict_in],get_game_list_stats([dict_in])],fi)
				xbmc.log(msg='IAGL:  Added %(game)s to new history file' % {'game': dict_in.get('info').get('originaltitle')}, level=xbmc.LOGDEBUG)
			with xbmcvfs.File(str(file_in).replace('.json','_stats.json'),'wb') as fi:
				json.dump(get_game_list_stats([dict_in]),fi)
				success = True
	return success

def define_ra_cmd(core_name,core_path,default_dict,ra_app_path):
	default_dict['@name'] = core_name
	default_dict['command'] = default_dict.get('command').replace("%APP_PATH_RA%",str(ra_app_path)).replace('%CORE_PATH%',str(core_path))
	return default_dict

def get_ra_info(core_in,ra_info_files):
	dict_out = dict()
	if core_in and ra_info_files:
		current_info = [x for x in ra_info_files if x.stem == core_in]
		if current_info:
			info_dict = get_ra_cfg_info_file(current_info[0])
			if info_dict:
				dict_out = info_dict
			else:
				xbmc.log(msg='IAGL:  No info could be found for the RA core %(file_in)s' % {'file_in': core_in}, level=xbmc.LOGDEBUG)
		else:
			xbmc.log(msg='IAGL:  No info could be found for the RA core %(file_in)s' % {'file_in': core_in}, level=xbmc.LOGDEBUG)
	return dict_out

def get_ra_libretro_config(ra_cfg_path,ra_app_path):
	ra_cfg = get_ra_cfg_info_file(ra_cfg_path)
	if ra_cfg:
		dict_out = dict()
		for kk in ['libretro_directory','libretro_info_path']:
			current_value = ra_cfg.get(kk)
			if current_value:
				if current_value.startswith(':'):
					current_app_path = ra_app_path.parent
					if str(current_app_path).endswith('MacOS'): #Special case for OSX
						current_app_path = ra_app_path.parents[2]
					dict_out[kk] = Path(current_app_path).joinpath(ra_cfg.get(kk).replace(':/','').replace(':\\','')).expanduser()
				else:
					dict_out[kk] = Path(xbmcvfs.translatePath(ra_cfg.get(kk))).expanduser()
			else:
				dict_out[kk] = None
		return dict_out
	else:
		return dict()

def get_ra_cfg_info_file(ra_path):
	if check_if_file_exists(ra_path):
		byte_string = None
		with xbmcvfs.File(str(ra_path)) as fi:
			byte_string = bytes(fi.readBytes())
		if byte_string:
			return {x[0].strip():x[-1].strip() for x in [l.split('=') for l in [p.replace('"','') for p in byte_string.decode(TEXT_ENCODING).replace('\r','\n').replace('\n\n','\n').split('\n')] if l and '=' in l] if isinstance(x,list) and len(x)==2}
		else:
			xbmc.log(msg='IAGL:  Error Retroarch cfg/info file %(value_in)s was empty' % {'value_in': file_in}, level=xbmc.LOGERROR)
			return None
	else:
		xbmc.log(msg='IAGL:  Error Retroarch cfg/info file %(value_in)s does not exist' % {'value_in': file_in}, level=xbmc.LOGERROR)
		return None

def loc_str(string_id_in):
	try:
		return ADDON_HANDLE.getLocalizedString(string_id_in)
	except:
		xbmc.log(msg='IAGL:  No translation available for %(string_id_in)s' % {'string_id_in': string_id_in}, level=xbmc.LOGERROR)
		return ''

def check_addondata_to_query(addon_files,userdata_files):
	query_out = list()
	for af in [x for x in zip(addon_files.get('files'),addon_files.get('header')) if x[0].name in [y.name for y in userdata_files.get('files')]]:
		if af[1].get('emu_version') != userdata_files.get('header')[[y.name for y in userdata_files.get('files')].index(af[0].name)].get('emu_version'):
			query_out.append((af[0],af[1].get('emu_name'),af[1].get('emu_version'),userdata_files.get('header')[[y.name for y in userdata_files.get('files')].index(af[0].name)].get('emu_version')))
			#file,name,new version,old version
		else:
			delete_file(af[0]) #The file already exists and is of the same version, so delete it
	return query_out

def get_game_download_dict(emu_baseurl=None,emu_downloadpath=None,emu_dl_source=None,emu_post_processor=None,emu_launcher=None,emu_default_addon=None,emu_ext_launch_cmd=None,game_url=None,game_downloadpath=None,game_post_processor=None,game_launcher=None,game_default_addon=None,game_ext_launch_cmd=None,game_emu_command=None,organize_default_dir=False,default_dir=None,emu_name=None):
	game_dl_dict = dict()
	if emu_dl_source and emu_baseurl and game_url and (emu_dl_source in ['Archive.org','Local Network Source','Kodi Library Source','Local File Source'] or 'http' in emu_dl_source):
		game_filename = url_unquote(game_url.split('/')[-1].split('%2F')[-1])
		game_dl_dict = {'dl_source':emu_dl_source,
					'baseurl':emu_baseurl,
					'url':game_url,
					'downloadpath':next(iter([x for x in [game_downloadpath,emu_downloadpath] if x]),'default'),
					'url_resolved':os.path.join(emu_baseurl,game_url.strip(os.sep).strip('/')),
					'filename':game_filename,
					'filename_no_ext':game_filename.split('.')[0],
					'filename_ext':game_filename.split('.')[-1].lower(),
					'post_processor':next(iter([x for x in [game_post_processor,emu_post_processor] if x]),'none'),
					'launcher':next(iter([x for x in [game_launcher,emu_launcher] if x]),'retroplayer'),
					'default_addon':next(iter([x for x in [game_default_addon,emu_default_addon] if x]),'none'),
					'ext_launch_cmd':next(iter([x for x in [game_ext_launch_cmd,emu_ext_launch_cmd] if x]),'none'),
					'emu_command':game_emu_command,
					'downloadpath_resolved':Path(emu_downloadpath).joinpath(game_filename).expanduser(),
					}
		xbmc.log(msg='IAGL:  Current game download parameters %(game_dl_dict)s' % {'game_dl_dict': game_dl_dict}, level=xbmc.LOGDEBUG)
		if organize_default_dir and game_dl_dict.get('downloadpath') == 'default' or str(game_dl_dict.get('downloadpath')) == str(default_dir) and emu_name:
			new_default_dir = check_userdata_directory(os.path.join(str(default_dir),emu_name))
			if new_default_dir:
				game_dl_dict['downloadpath'] = str(new_default_dir)
				game_dl_dict['downloadpath_resolved'] = Path(game_dl_dict.get('downloadpath')).joinpath(game_filename).expanduser()
		if emu_post_processor in ['launch_mame_softlist_cdimono1']: #Download to a specific folder depending on the post process command
			post_process_dir = dict(zip(['launch_mame_softlist_cdimono1'],['cdimono1']))
			game_dl_dict['downloadpath_resolved'] = Path(game_dl_dict.get('downloadpath_resolved').parent).joinpath(post_process_dir.get(emu_post_processor),game_dl_dict.get('downloadpath_resolved').name).expanduser()
			check_userdata_directory(game_dl_dict.get('downloadpath_resolved').parent)
		if game_dl_dict.get('downloadpath_resolved').parent.exists():
			if game_dl_dict.get('filename_ext') not in ARCHIVE_FILETYPES: #If file to be downloaded is not an archive, it should match exactly with a local file - currenly works because all post processed filetypes are archives.  This may have to be updated in the future
				if check_if_file_exists(game_dl_dict.get('downloadpath_resolved')):
					game_dl_dict['matching_existing_files'] = [game_dl_dict.get('downloadpath_resolved')]
				else:
					game_dl_dict['matching_existing_files'] = []
			else: #If the file to be downloaded is an archive, the name without extension should match with a local file
				game_dl_dict['matching_existing_files'] = [x for x in game_dl_dict.get('downloadpath_resolved').parent.glob('**/'+glob.escape(game_dl_dict.get('downloadpath_resolved').stem)+'[.]*') if x.suffix.lower() not in IGNORE_THESE_FILETYPES and x.name.lower() not in IGNORE_THESE_FILES]
		elif xbmcvfs.exists(str(game_dl_dict.get('downloadpath'))): #Kodi network source save spot (like smb address) need to use xbmcvfs to check local files
			if game_dl_dict.get('filename_ext') not in ARCHIVE_FILETYPES:
				if check_if_file_exists(str(game_dl_dict.get('downloadpath_resolved'))):
					game_dl_dict['matching_existing_files'] = [str(game_dl_dict.get('downloadpath_resolved'))]
				else:
					game_dl_dict['matching_existing_files'] = []
			else:
				game_dl_dict['matching_existing_files'] = [x for x in get_all_files_in_directory_xbmcvfs(str(game_dl_dict.get('downloadpath'))) if os.path.split(os.path.splitext(x)[0])[-1] == game_dl_dict.get('filename_no_ext') and os.path.splitext(x)[-1].lower() not in IGNORE_THESE_FILETYPES and os.path.split(os.path.splitext(x)[0])[-1] not in IGNORE_THESE_FILES]
		else:
			game_dl_dict['matching_existing_files'] = []
		if game_dl_dict.get('emu_command'):
			game_dl_dict['matching_existing_files'] = list(set(game_dl_dict.get('matching_existing_files')+[x for x in game_dl_dict.get('downloadpath_resolved').parent.glob('**/'+glob.escape(game_dl_dict.get('emu_command'))+'*') if x.suffix.lower() not in IGNORE_THESE_FILETYPES and x.name.lower() not in IGNORE_THESE_FILES]))
		if game_dl_dict.get('dl_source') in ['Archive.org']:
			game_dl_dict['downloader'] = 'archive_org'
		elif 'http' in game_dl_dict.get('dl_source'):
			game_dl_dict['downloader'] = 'generic'
		elif game_dl_dict.get('dl_source') in ['Local Network Source','Kodi Library Source','Local File Source']:
			game_dl_dict['downloader'] = 'local_source'
		else:
			game_dl_dict['downloader'] = None
	return game_dl_dict


def dict_to_game_xml(game=None):
	xml_out = None
	if isinstance(game,dict) and game.get('values') and game.get('info'):
		dict_out_keys = ['@name','plot','releasedate','year','studio','genre','rating','ESRB','videoid','description','route','nplayers','perspective']+['boxart%(nn)s'%{'nn':x} for x in range(1,11)]+['snapshot%(nn)s'%{'nn':x} for x in range(1,11)]+['banner%(nn)s'%{'nn':x} for x in range(1,11)]+['fanart%(nn)s'%{'nn':x} for x in range(1,11)]+['clearlogo%(nn)s'%{'nn':x} for x in range(1,11)]
		dict_out = {'game': dict(zip(dict_out_keys,[None for x in dict_out_keys]))}
		dict_out_mapping = dict()
		dict_out_mapping['values'] = dict(zip(['@name'],['label2']))
		dict_out_mapping['info'] = dict(zip(['plot','releasedate','year','studio','genre','rating','ESRB','videoid'],['plot','date','year','studio','genre','rating','mpaa','trailer']))
		dict_out_mapping['properties'] = dict(zip(['description','route','nplayers','perspective'],['description','route','nplayers','perspective']))
		dict_out_art_mapping = dict(zip(['game_boxarts','game_banners','game_snapshots','game_logos','game_fanarts'],['boxart','banner','snapshot','clearlogo','fanart']))
		for kk in dict_out_mapping.keys():
			for k,v in dict_out_mapping.get(kk).items():
				if isinstance(game.get(kk).get(v),str):
					if k in ['@name']:
						dict_out['game'][k] = url_unquote(game.get(kk).get(v))
					else:
						dict_out['game'][k] = game.get(kk).get(v)
				elif isinstance(game.get(kk).get(v),list):
					dict_out['game'][k] = ','.join(game.get(kk).get(v))
		if dict_out.get('game').get('videoid'):
			dict_out['game']['videoid'] = dict_out.get('game').get('videoid').split('=')[-1]
		for k,v in dict_out_art_mapping.items():
			if game.get('properties') and isinstance(game.get('properties').get(k),str):
				for ii,art in enumerate(json.loads(game.get('properties').get(k))):
					dict_out['game']['%(type)s%(nn)s'%{'type':v,'nn':ii+1}] = art
		for kk in dict_out_keys:
			if not dict_out.get('game').get(kk):
				dict_out['game'].pop(kk, None)
		try:
			xml_out = xmltodict.unparse(dict_out, pretty=True).replace('<?xml version="1.0" encoding="utf-8"?>\n','')
		except Exception as exc:
			xbmc.log(msg='IAGL:  Error generating favorites xml.  Exception %(exc)s' % {'exc': exc}, level=xbmc.LOGERROR)
	return xml_out

def add_game_to_favorites(filename_in=None,game=None):
	success = False
	if isinstance(game,dict) and check_if_file_exists(filename_in):
		xml_out = dict_to_game_xml(game=game)+'\n</datafile>'
		if isinstance(xml_out,str) and '<game ' in xml_out and '</game>' in xml_out:
			success = write_text_to_file(filename_in.read_text(encoding=TEXT_ENCODING).replace('</datafile>',xml_out),filename_in)
	return success

def remove_game_from_favorites(filename_in=None,game=None):
	success = False
	if isinstance(game,str) and check_if_file_exists(filename_in):
		games = get_xml_games(filename_in)
		if game in [x.get('@name') for x in games]:
			if len([x for x in games if x.get('@name')!=game])>=1:
				games_header = get_xml_header_path_et_fromstring(filename_in)
				if games_header:
					xml_out = xmltodict.unparse({'datafile':{'header':games_header}}, pretty=True).replace('</datafile>',''.join([xmltodict.unparse({'game':x},pretty=True).replace('<?xml version="1.0" encoding="utf-8"?>','') for x in games if x and x.get('@name') != game]))+'\n</datafile>'
					if '<datafile>' in xml_out and '</datafile>' in xml_out:
						success = write_text_to_file(xml_out,filename_in)
					else:
						xbmc.log(msg='IAGL:  The xml appears malformed so it will not be updated.', level=xbmc.LOGERROR)
				else:
					xbmc.log(msg='IAGL:  Unable to parse the header in the file %(filename_in)s'%{'filename_in':filename_in}, level=xbmc.LOGERROR)
			else:
				xbmc.log(msg='IAGL:  Unable to delete the game from the file because there is only one game listed.  Delete the list if desired.', level=xbmc.LOGERROR)
		else:
			xbmc.log(msg='IAGL:  Unable find the game %(game)s in the file %(filename_in)s'%{'game':game, 'filename_in':filename_in}, level=xbmc.LOGERROR)
	return success

def bytes_to_string_size(value, format='%.1f'):
	if isinstance(value,int) or isinstance(value,float): # or (isinstance(num,str) and num.isdigit())
		suffix = ('kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB')
		base = 1024
		value_bytes = float(value)
		if abs(value_bytes) < base:
			return '%d Bytes' % value_bytes
		for i, s in enumerate(suffix):
			unit = base ** (i + 2)
			if abs(value_bytes) < unit:
				return (format + ' %s') % ((base * value_bytes / unit), s)
		return (format + ' %s') % ((base * value_bytes / unit), s)
	else:
		return None

# def get_all_files_in_directory_xbmcvfs(directory_in,current_files=None):
# 	dirs_in_dir, files_in_dir = xbmcvfs.listdir(os.path.join(directory_in,''))
# 	if isinstance(current_files,list):
# 		current_files = current_files+[os.path.join(directory_in,ff) for ff in files_in_dir if ff]
# 	else:
# 		current_files = [os.path.join(directory_in,ff) for ff in files_in_dir if ff]
# 	for dd in dirs_in_dir:
# 		current_files = get_all_files_in_directory_xbmcvfs(os.path.join(directory_in,dd,''),current_files)
# 	return current_files

def generate_pointer_file(filename_in=None,pointer_file_type=None,pointer_contents=None,directory=None,default_dir=None):
	filename_out = None
	if filename_in and pointer_file_type:
		if directory:
			filename_out = os.path.join(directory,filename_in.stem+pointer_file_type)
		else:
			filename_out = os.path.join(str(default_dir),filename_in.stem+pointer_file_type)
		if not pointer_contents:
			pointer_contents = ''
		if write_text_to_file(text_in=pointer_contents,filename_in=filename_out):
			return filename_out
		else:
			return None

def get_all_files_in_directory_xbmcvfs(directory_in):
	directory_in = directory_in
	current_files = list()
	dirs_in_dir, files_in_dir = xbmcvfs.listdir(os.path.join(directory_in,''))
	current_files = [os.path.join(directory_in,ff) for ff in files_in_dir if ff is not None]
	for dd in dirs_in_dir:
		dirs_in_dir2, files_in_dir2 = xbmcvfs.listdir(os.path.join(directory_in,dd,''))
		current_files = current_files+[os.path.join(directory_in,dd,ff) for ff in files_in_dir2 if ff is not None]
		for dd2 in dirs_in_dir2:
			dirs_in_dir3, files_in_dir3 = xbmcvfs.listdir(os.path.join(directory_in,dd,dd2,''))
			current_files = current_files+[os.path.join(directory_in,dd,dd2,ff) for ff in files_in_dir3 if ff is not None]
			for dd3 in dirs_in_dir3:
				dirs_in_dir4, files_in_dir4 = xbmcvfs.listdir(os.path.join(directory_in,dd,dd2,dd3,'')) #Go down 4 levels to look for various files for launching
				current_files = current_files+[os.path.join(directory_in,dd,dd2,dd3,ff) for ff in files_in_dir4 if ff is not None]
	return current_files

def clean_file_folder_name(text_in):
	text_out = text_in
	if isinstance(text_in,str):
		text_out = re.sub(' +',' ',''.join(c for c in url_unquote(text_out) if c.isalnum() or c in [' ','_']).rstrip())
		text_out = re.sub('dis[ck] [0-9]+','',text_out,flags=re.I)
		text_out = re.sub(' +','_',text_out)
	return text_out

def check_and_close_notification(notification_id=None):
	if not notification_id:
		notification_id = 'notification'
	is_closed = False
	for ii in range(4):
		if xbmc.getCondVisibility('Window.IsActive(%(notification_id)s)'%{'notification_id':notification_id}):
			xbmc.executebuiltin('Dialog.Close(%(notification_id)s,true)'%{'notification_id':notification_id})
			xbmc.sleep(NOTIFICATION_DEINIT_TIME)
			if not xbmc.getCondVisibility('Window.IsActive(%(notification_id)s)'%{'notification_id':notification_id}):	
				is_closed=True
				break
		else:
			is_closed=True
			break
		if ii==3:
			xbmc.log(msg='IAGL:  Unable to close the notification window', level=xbmc.LOGERROR)
	return is_closed

def enqueue_output(out, queue):
	for line in iter(out.readline, b''):
		queue.put(line)
	out.close()

def get_uuid():
	return str(uuid.uuid4()).split('-')[0]

def generate_discord_announcement(discord_id=None,username=None,uuid=None,game=None):
	if isinstance(username,str) and isinstance(uuid,str) and isinstance(game,dict):
		if isinstance(discord_id,str) and discord_id.isdigit():
			content_username = '<@!%(id)s>'%{'id':discord_id}
		else:
			content_username = username
		disc_json = {'username': 'IAGL Netplay Bot',
		'avatar_url': 'https://cdn.discordapp.com/avatars/696566666598809641/9fa63a6bd4a8783e9eaa2be13f2adae4.png',
		'content': '%(username)s has started hosting %(game_title)s'%{'username':content_username,'game_title':game.get('info').get('originaltitle')},
		'embeds': [{'author': {'name': username},
		'title': game.get('info').get('originaltitle'),
		'description': 'Come play %(game_title)s with %(username)s'%{'game_title':game.get('info').get('originaltitle'),'username':username},
		'timestamp': time.strftime('%Y-%m-%dT%H:%M:%SZ',time.gmtime()),
		'fields': [{'name':'system',
					'value': next(iter([game.get('properties').get('platform_description')]),'Unknown'),
					'inline': True},
					{'name':'genre',
					'value': next(iter([','.join(game.get('info').get('genre'))]),'None'),
					'inline': True},
					{'name':'route',
					'value': game.get('properties').get('route'),
					'inline': False},
					{'name':'game_id',
					 'value': game.get('values').get('label2'),
					 'inline': False},
					 {'name':'uuid',
					 'value': uuid,
					 'inline': False},
					],
		'image': {'url':next(iter([x for x in [game.get('art').get('poster'),game.get('art').get('thumb')] if 'http' in x]),'https://cdn.discordapp.com/avatars/696566666598809641/9fa63a6bd4a8783e9eaa2be13f2adae4.png')}}]}
		with requests.Session() as s:
			response = s.post('https://discordapp.com/api/webhooks/%(chan)s/%(value)s'%{'chan':'696566666598809641','value':get_t_string('cDNaRo6zXMlTlwC-hnEnDXEEK6Lh_pxYnywkAyjdkGAIlmkza5QeTdQThHpXnUMXLJNt')},json=disc_json)
		return response.ok
	else:
		return False

def map_lobby_listitem_dict(libretro_dict=None,discord_dict=None,filter_lobby=True):
	dict_out = None
	current_query=dict()
	uuid_match = next(iter(get_game_tags(libretro_dict.get('username'))),None)
	current_discords = [dict(zip([z.get('name') for z in y[0]]+['author','description','timestamp','image'],[z.get('value') for z in y[0]]+[y[1].get('name'),y[2],y[3],y[4].get('url')])) for y in [(x.get('embeds')[0].get('fields'),x.get('embeds')[0].get('author'),x.get('embeds')[0].get('description'),x.get('embeds')[0].get('timestamp'),x.get('embeds')[0].get('image')) for x in discord_dict if x.get('embeds') and isinstance(x.get('embeds'),list) and x.get('embeds')[0].get('fields')] if any([z.get('name') == 'uuid' for z in y[0]])]
	discord_match = next(iter([x for x in current_discords if uuid_match and x.get('uuid')==uuid_match]),None)
	country_codes = [{"name":"Afghanistan","alpha-2":"AF","alpha-3":"AFG","country-code":"004","iso_3166-2":"ISO 3166-2:AF","region":"Asia","sub-region":"Southern Asia","intermediate-region":"","region-code":"142","sub-region-code":"034","intermediate-region-code":""},{"name":"Åland Islands","alpha-2":"AX","alpha-3":"ALA","country-code":"248","iso_3166-2":"ISO 3166-2:AX","region":"Europe","sub-region":"Northern Europe","intermediate-region":"","region-code":"150","sub-region-code":"154","intermediate-region-code":""},{"name":"Albania","alpha-2":"AL","alpha-3":"ALB","country-code":"008","iso_3166-2":"ISO 3166-2:AL","region":"Europe","sub-region":"Southern Europe","intermediate-region":"","region-code":"150","sub-region-code":"039","intermediate-region-code":""},{"name":"Algeria","alpha-2":"DZ","alpha-3":"DZA","country-code":"012","iso_3166-2":"ISO 3166-2:DZ","region":"Africa","sub-region":"Northern Africa","intermediate-region":"","region-code":"002","sub-region-code":"015","intermediate-region-code":""},{"name":"American Samoa","alpha-2":"AS","alpha-3":"ASM","country-code":"016","iso_3166-2":"ISO 3166-2:AS","region":"Oceania","sub-region":"Polynesia","intermediate-region":"","region-code":"009","sub-region-code":"061","intermediate-region-code":""},{"name":"Andorra","alpha-2":"AD","alpha-3":"AND","country-code":"020","iso_3166-2":"ISO 3166-2:AD","region":"Europe","sub-region":"Southern Europe","intermediate-region":"","region-code":"150","sub-region-code":"039","intermediate-region-code":""},{"name":"Angola","alpha-2":"AO","alpha-3":"AGO","country-code":"024","iso_3166-2":"ISO 3166-2:AO","region":"Africa","sub-region":"Sub-Saharan Africa","intermediate-region":"Middle Africa","region-code":"002","sub-region-code":"202","intermediate-region-code":"017"},{"name":"Anguilla","alpha-2":"AI","alpha-3":"AIA","country-code":"660","iso_3166-2":"ISO 3166-2:AI","region":"Americas","sub-region":"Latin America and the Caribbean","intermediate-region":"Caribbean","region-code":"019","sub-region-code":"419","intermediate-region-code":"029"},{"name":"Antarctica","alpha-2":"AQ","alpha-3":"ATA","country-code":"010","iso_3166-2":"ISO 3166-2:AQ","region":"","sub-region":"","intermediate-region":"","region-code":"","sub-region-code":"","intermediate-region-code":""},{"name":"Antigua and Barbuda","alpha-2":"AG","alpha-3":"ATG","country-code":"028","iso_3166-2":"ISO 3166-2:AG","region":"Americas","sub-region":"Latin America and the Caribbean","intermediate-region":"Caribbean","region-code":"019","sub-region-code":"419","intermediate-region-code":"029"},{"name":"Argentina","alpha-2":"AR","alpha-3":"ARG","country-code":"032","iso_3166-2":"ISO 3166-2:AR","region":"Americas","sub-region":"Latin America and the Caribbean","intermediate-region":"South America","region-code":"019","sub-region-code":"419","intermediate-region-code":"005"},{"name":"Armenia","alpha-2":"AM","alpha-3":"ARM","country-code":"051","iso_3166-2":"ISO 3166-2:AM","region":"Asia","sub-region":"Western Asia","intermediate-region":"","region-code":"142","sub-region-code":"145","intermediate-region-code":""},{"name":"Aruba","alpha-2":"AW","alpha-3":"ABW","country-code":"533","iso_3166-2":"ISO 3166-2:AW","region":"Americas","sub-region":"Latin America and the Caribbean","intermediate-region":"Caribbean","region-code":"019","sub-region-code":"419","intermediate-region-code":"029"},{"name":"Australia","alpha-2":"AU","alpha-3":"AUS","country-code":"036","iso_3166-2":"ISO 3166-2:AU","region":"Oceania","sub-region":"Australia and New Zealand","intermediate-region":"","region-code":"009","sub-region-code":"053","intermediate-region-code":""},{"name":"Austria","alpha-2":"AT","alpha-3":"AUT","country-code":"040","iso_3166-2":"ISO 3166-2:AT","region":"Europe","sub-region":"Western Europe","intermediate-region":"","region-code":"150","sub-region-code":"155","intermediate-region-code":""},{"name":"Azerbaijan","alpha-2":"AZ","alpha-3":"AZE","country-code":"031","iso_3166-2":"ISO 3166-2:AZ","region":"Asia","sub-region":"Western Asia","intermediate-region":"","region-code":"142","sub-region-code":"145","intermediate-region-code":""},{"name":"Bahamas","alpha-2":"BS","alpha-3":"BHS","country-code":"044","iso_3166-2":"ISO 3166-2:BS","region":"Americas","sub-region":"Latin America and the Caribbean","intermediate-region":"Caribbean","region-code":"019","sub-region-code":"419","intermediate-region-code":"029"},{"name":"Bahrain","alpha-2":"BH","alpha-3":"BHR","country-code":"048","iso_3166-2":"ISO 3166-2:BH","region":"Asia","sub-region":"Western Asia","intermediate-region":"","region-code":"142","sub-region-code":"145","intermediate-region-code":""},{"name":"Bangladesh","alpha-2":"BD","alpha-3":"BGD","country-code":"050","iso_3166-2":"ISO 3166-2:BD","region":"Asia","sub-region":"Southern Asia","intermediate-region":"","region-code":"142","sub-region-code":"034","intermediate-region-code":""},{"name":"Barbados","alpha-2":"BB","alpha-3":"BRB","country-code":"052","iso_3166-2":"ISO 3166-2:BB","region":"Americas","sub-region":"Latin America and the Caribbean","intermediate-region":"Caribbean","region-code":"019","sub-region-code":"419","intermediate-region-code":"029"},{"name":"Belarus","alpha-2":"BY","alpha-3":"BLR","country-code":"112","iso_3166-2":"ISO 3166-2:BY","region":"Europe","sub-region":"Eastern Europe","intermediate-region":"","region-code":"150","sub-region-code":"151","intermediate-region-code":""},{"name":"Belgium","alpha-2":"BE","alpha-3":"BEL","country-code":"056","iso_3166-2":"ISO 3166-2:BE","region":"Europe","sub-region":"Western Europe","intermediate-region":"","region-code":"150","sub-region-code":"155","intermediate-region-code":""},{"name":"Belize","alpha-2":"BZ","alpha-3":"BLZ","country-code":"084","iso_3166-2":"ISO 3166-2:BZ","region":"Americas","sub-region":"Latin America and the Caribbean","intermediate-region":"Central America","region-code":"019","sub-region-code":"419","intermediate-region-code":"013"},{"name":"Benin","alpha-2":"BJ","alpha-3":"BEN","country-code":"204","iso_3166-2":"ISO 3166-2:BJ","region":"Africa","sub-region":"Sub-Saharan Africa","intermediate-region":"Western Africa","region-code":"002","sub-region-code":"202","intermediate-region-code":"011"},{"name":"Bermuda","alpha-2":"BM","alpha-3":"BMU","country-code":"060","iso_3166-2":"ISO 3166-2:BM","region":"Americas","sub-region":"Northern America","intermediate-region":"","region-code":"019","sub-region-code":"021","intermediate-region-code":""},{"name":"Bhutan","alpha-2":"BT","alpha-3":"BTN","country-code":"064","iso_3166-2":"ISO 3166-2:BT","region":"Asia","sub-region":"Southern Asia","intermediate-region":"","region-code":"142","sub-region-code":"034","intermediate-region-code":""},{"name":"Bolivia (Plurinational State of)","alpha-2":"BO","alpha-3":"BOL","country-code":"068","iso_3166-2":"ISO 3166-2:BO","region":"Americas","sub-region":"Latin America and the Caribbean","intermediate-region":"South America","region-code":"019","sub-region-code":"419","intermediate-region-code":"005"},{"name":"Bonaire, Sint Eustatius and Saba","alpha-2":"BQ","alpha-3":"BES","country-code":"535","iso_3166-2":"ISO 3166-2:BQ","region":"Americas","sub-region":"Latin America and the Caribbean","intermediate-region":"Caribbean","region-code":"019","sub-region-code":"419","intermediate-region-code":"029"},{"name":"Bosnia and Herzegovina","alpha-2":"BA","alpha-3":"BIH","country-code":"070","iso_3166-2":"ISO 3166-2:BA","region":"Europe","sub-region":"Southern Europe","intermediate-region":"","region-code":"150","sub-region-code":"039","intermediate-region-code":""},{"name":"Botswana","alpha-2":"BW","alpha-3":"BWA","country-code":"072","iso_3166-2":"ISO 3166-2:BW","region":"Africa","sub-region":"Sub-Saharan Africa","intermediate-region":"Southern Africa","region-code":"002","sub-region-code":"202","intermediate-region-code":"018"},{"name":"Bouvet Island","alpha-2":"BV","alpha-3":"BVT","country-code":"074","iso_3166-2":"ISO 3166-2:BV","region":"Americas","sub-region":"Latin America and the Caribbean","intermediate-region":"South America","region-code":"019","sub-region-code":"419","intermediate-region-code":"005"},{"name":"Brazil","alpha-2":"BR","alpha-3":"BRA","country-code":"076","iso_3166-2":"ISO 3166-2:BR","region":"Americas","sub-region":"Latin America and the Caribbean","intermediate-region":"South America","region-code":"019","sub-region-code":"419","intermediate-region-code":"005"},{"name":"British Indian Ocean Territory","alpha-2":"IO","alpha-3":"IOT","country-code":"086","iso_3166-2":"ISO 3166-2:IO","region":"Africa","sub-region":"Sub-Saharan Africa","intermediate-region":"Eastern Africa","region-code":"002","sub-region-code":"202","intermediate-region-code":"014"},{"name":"Brunei Darussalam","alpha-2":"BN","alpha-3":"BRN","country-code":"096","iso_3166-2":"ISO 3166-2:BN","region":"Asia","sub-region":"South-eastern Asia","intermediate-region":"","region-code":"142","sub-region-code":"035","intermediate-region-code":""},{"name":"Bulgaria","alpha-2":"BG","alpha-3":"BGR","country-code":"100","iso_3166-2":"ISO 3166-2:BG","region":"Europe","sub-region":"Eastern Europe","intermediate-region":"","region-code":"150","sub-region-code":"151","intermediate-region-code":""},{"name":"Burkina Faso","alpha-2":"BF","alpha-3":"BFA","country-code":"854","iso_3166-2":"ISO 3166-2:BF","region":"Africa","sub-region":"Sub-Saharan Africa","intermediate-region":"Western Africa","region-code":"002","sub-region-code":"202","intermediate-region-code":"011"},{"name":"Burundi","alpha-2":"BI","alpha-3":"BDI","country-code":"108","iso_3166-2":"ISO 3166-2:BI","region":"Africa","sub-region":"Sub-Saharan Africa","intermediate-region":"Eastern Africa","region-code":"002","sub-region-code":"202","intermediate-region-code":"014"},{"name":"Cabo Verde","alpha-2":"CV","alpha-3":"CPV","country-code":"132","iso_3166-2":"ISO 3166-2:CV","region":"Africa","sub-region":"Sub-Saharan Africa","intermediate-region":"Western Africa","region-code":"002","sub-region-code":"202","intermediate-region-code":"011"},{"name":"Cambodia","alpha-2":"KH","alpha-3":"KHM","country-code":"116","iso_3166-2":"ISO 3166-2:KH","region":"Asia","sub-region":"South-eastern Asia","intermediate-region":"","region-code":"142","sub-region-code":"035","intermediate-region-code":""},{"name":"Cameroon","alpha-2":"CM","alpha-3":"CMR","country-code":"120","iso_3166-2":"ISO 3166-2:CM","region":"Africa","sub-region":"Sub-Saharan Africa","intermediate-region":"Middle Africa","region-code":"002","sub-region-code":"202","intermediate-region-code":"017"},{"name":"Canada","alpha-2":"CA","alpha-3":"CAN","country-code":"124","iso_3166-2":"ISO 3166-2:CA","region":"Americas","sub-region":"Northern America","intermediate-region":"","region-code":"019","sub-region-code":"021","intermediate-region-code":""},{"name":"Cayman Islands","alpha-2":"KY","alpha-3":"CYM","country-code":"136","iso_3166-2":"ISO 3166-2:KY","region":"Americas","sub-region":"Latin America and the Caribbean","intermediate-region":"Caribbean","region-code":"019","sub-region-code":"419","intermediate-region-code":"029"},{"name":"Central African Republic","alpha-2":"CF","alpha-3":"CAF","country-code":"140","iso_3166-2":"ISO 3166-2:CF","region":"Africa","sub-region":"Sub-Saharan Africa","intermediate-region":"Middle Africa","region-code":"002","sub-region-code":"202","intermediate-region-code":"017"},{"name":"Chad","alpha-2":"TD","alpha-3":"TCD","country-code":"148","iso_3166-2":"ISO 3166-2:TD","region":"Africa","sub-region":"Sub-Saharan Africa","intermediate-region":"Middle Africa","region-code":"002","sub-region-code":"202","intermediate-region-code":"017"},{"name":"Chile","alpha-2":"CL","alpha-3":"CHL","country-code":"152","iso_3166-2":"ISO 3166-2:CL","region":"Americas","sub-region":"Latin America and the Caribbean","intermediate-region":"South America","region-code":"019","sub-region-code":"419","intermediate-region-code":"005"},{"name":"China","alpha-2":"CN","alpha-3":"CHN","country-code":"156","iso_3166-2":"ISO 3166-2:CN","region":"Asia","sub-region":"Eastern Asia","intermediate-region":"","region-code":"142","sub-region-code":"030","intermediate-region-code":""},{"name":"Christmas Island","alpha-2":"CX","alpha-3":"CXR","country-code":"162","iso_3166-2":"ISO 3166-2:CX","region":"Oceania","sub-region":"Australia and New Zealand","intermediate-region":"","region-code":"009","sub-region-code":"053","intermediate-region-code":""},{"name":"Cocos (Keeling) Islands","alpha-2":"CC","alpha-3":"CCK","country-code":"166","iso_3166-2":"ISO 3166-2:CC","region":"Oceania","sub-region":"Australia and New Zealand","intermediate-region":"","region-code":"009","sub-region-code":"053","intermediate-region-code":""},{"name":"Colombia","alpha-2":"CO","alpha-3":"COL","country-code":"170","iso_3166-2":"ISO 3166-2:CO","region":"Americas","sub-region":"Latin America and the Caribbean","intermediate-region":"South America","region-code":"019","sub-region-code":"419","intermediate-region-code":"005"},{"name":"Comoros","alpha-2":"KM","alpha-3":"COM","country-code":"174","iso_3166-2":"ISO 3166-2:KM","region":"Africa","sub-region":"Sub-Saharan Africa","intermediate-region":"Eastern Africa","region-code":"002","sub-region-code":"202","intermediate-region-code":"014"},{"name":"Congo","alpha-2":"CG","alpha-3":"COG","country-code":"178","iso_3166-2":"ISO 3166-2:CG","region":"Africa","sub-region":"Sub-Saharan Africa","intermediate-region":"Middle Africa","region-code":"002","sub-region-code":"202","intermediate-region-code":"017"},{"name":"Congo, Democratic Republic of the","alpha-2":"CD","alpha-3":"COD","country-code":"180","iso_3166-2":"ISO 3166-2:CD","region":"Africa","sub-region":"Sub-Saharan Africa","intermediate-region":"Middle Africa","region-code":"002","sub-region-code":"202","intermediate-region-code":"017"},{"name":"Cook Islands","alpha-2":"CK","alpha-3":"COK","country-code":"184","iso_3166-2":"ISO 3166-2:CK","region":"Oceania","sub-region":"Polynesia","intermediate-region":"","region-code":"009","sub-region-code":"061","intermediate-region-code":""},{"name":"Costa Rica","alpha-2":"CR","alpha-3":"CRI","country-code":"188","iso_3166-2":"ISO 3166-2:CR","region":"Americas","sub-region":"Latin America and the Caribbean","intermediate-region":"Central America","region-code":"019","sub-region-code":"419","intermediate-region-code":"013"},{"name":"Côte d'Ivoire","alpha-2":"CI","alpha-3":"CIV","country-code":"384","iso_3166-2":"ISO 3166-2:CI","region":"Africa","sub-region":"Sub-Saharan Africa","intermediate-region":"Western Africa","region-code":"002","sub-region-code":"202","intermediate-region-code":"011"},{"name":"Croatia","alpha-2":"HR","alpha-3":"HRV","country-code":"191","iso_3166-2":"ISO 3166-2:HR","region":"Europe","sub-region":"Southern Europe","intermediate-region":"","region-code":"150","sub-region-code":"039","intermediate-region-code":""},{"name":"Cuba","alpha-2":"CU","alpha-3":"CUB","country-code":"192","iso_3166-2":"ISO 3166-2:CU","region":"Americas","sub-region":"Latin America and the Caribbean","intermediate-region":"Caribbean","region-code":"019","sub-region-code":"419","intermediate-region-code":"029"},{"name":"Curaçao","alpha-2":"CW","alpha-3":"CUW","country-code":"531","iso_3166-2":"ISO 3166-2:CW","region":"Americas","sub-region":"Latin America and the Caribbean","intermediate-region":"Caribbean","region-code":"019","sub-region-code":"419","intermediate-region-code":"029"},{"name":"Cyprus","alpha-2":"CY","alpha-3":"CYP","country-code":"196","iso_3166-2":"ISO 3166-2:CY","region":"Asia","sub-region":"Western Asia","intermediate-region":"","region-code":"142","sub-region-code":"145","intermediate-region-code":""},{"name":"Czechia","alpha-2":"CZ","alpha-3":"CZE","country-code":"203","iso_3166-2":"ISO 3166-2:CZ","region":"Europe","sub-region":"Eastern Europe","intermediate-region":"","region-code":"150","sub-region-code":"151","intermediate-region-code":""},{"name":"Denmark","alpha-2":"DK","alpha-3":"DNK","country-code":"208","iso_3166-2":"ISO 3166-2:DK","region":"Europe","sub-region":"Northern Europe","intermediate-region":"","region-code":"150","sub-region-code":"154","intermediate-region-code":""},{"name":"Djibouti","alpha-2":"DJ","alpha-3":"DJI","country-code":"262","iso_3166-2":"ISO 3166-2:DJ","region":"Africa","sub-region":"Sub-Saharan Africa","intermediate-region":"Eastern Africa","region-code":"002","sub-region-code":"202","intermediate-region-code":"014"},{"name":"Dominica","alpha-2":"DM","alpha-3":"DMA","country-code":"212","iso_3166-2":"ISO 3166-2:DM","region":"Americas","sub-region":"Latin America and the Caribbean","intermediate-region":"Caribbean","region-code":"019","sub-region-code":"419","intermediate-region-code":"029"},{"name":"Dominican Republic","alpha-2":"DO","alpha-3":"DOM","country-code":"214","iso_3166-2":"ISO 3166-2:DO","region":"Americas","sub-region":"Latin America and the Caribbean","intermediate-region":"Caribbean","region-code":"019","sub-region-code":"419","intermediate-region-code":"029"},{"name":"Ecuador","alpha-2":"EC","alpha-3":"ECU","country-code":"218","iso_3166-2":"ISO 3166-2:EC","region":"Americas","sub-region":"Latin America and the Caribbean","intermediate-region":"South America","region-code":"019","sub-region-code":"419","intermediate-region-code":"005"},{"name":"Egypt","alpha-2":"EG","alpha-3":"EGY","country-code":"818","iso_3166-2":"ISO 3166-2:EG","region":"Africa","sub-region":"Northern Africa","intermediate-region":"","region-code":"002","sub-region-code":"015","intermediate-region-code":""},{"name":"El Salvador","alpha-2":"SV","alpha-3":"SLV","country-code":"222","iso_3166-2":"ISO 3166-2:SV","region":"Americas","sub-region":"Latin America and the Caribbean","intermediate-region":"Central America","region-code":"019","sub-region-code":"419","intermediate-region-code":"013"},{"name":"Equatorial Guinea","alpha-2":"GQ","alpha-3":"GNQ","country-code":"226","iso_3166-2":"ISO 3166-2:GQ","region":"Africa","sub-region":"Sub-Saharan Africa","intermediate-region":"Middle Africa","region-code":"002","sub-region-code":"202","intermediate-region-code":"017"},{"name":"Eritrea","alpha-2":"ER","alpha-3":"ERI","country-code":"232","iso_3166-2":"ISO 3166-2:ER","region":"Africa","sub-region":"Sub-Saharan Africa","intermediate-region":"Eastern Africa","region-code":"002","sub-region-code":"202","intermediate-region-code":"014"},{"name":"Estonia","alpha-2":"EE","alpha-3":"EST","country-code":"233","iso_3166-2":"ISO 3166-2:EE","region":"Europe","sub-region":"Northern Europe","intermediate-region":"","region-code":"150","sub-region-code":"154","intermediate-region-code":""},{"name":"Eswatini","alpha-2":"SZ","alpha-3":"SWZ","country-code":"748","iso_3166-2":"ISO 3166-2:SZ","region":"Africa","sub-region":"Sub-Saharan Africa","intermediate-region":"Southern Africa","region-code":"002","sub-region-code":"202","intermediate-region-code":"018"},{"name":"Ethiopia","alpha-2":"ET","alpha-3":"ETH","country-code":"231","iso_3166-2":"ISO 3166-2:ET","region":"Africa","sub-region":"Sub-Saharan Africa","intermediate-region":"Eastern Africa","region-code":"002","sub-region-code":"202","intermediate-region-code":"014"},{"name":"Falkland Islands (Malvinas)","alpha-2":"FK","alpha-3":"FLK","country-code":"238","iso_3166-2":"ISO 3166-2:FK","region":"Americas","sub-region":"Latin America and the Caribbean","intermediate-region":"South America","region-code":"019","sub-region-code":"419","intermediate-region-code":"005"},{"name":"Faroe Islands","alpha-2":"FO","alpha-3":"FRO","country-code":"234","iso_3166-2":"ISO 3166-2:FO","region":"Europe","sub-region":"Northern Europe","intermediate-region":"","region-code":"150","sub-region-code":"154","intermediate-region-code":""},{"name":"Fiji","alpha-2":"FJ","alpha-3":"FJI","country-code":"242","iso_3166-2":"ISO 3166-2:FJ","region":"Oceania","sub-region":"Melanesia","intermediate-region":"","region-code":"009","sub-region-code":"054","intermediate-region-code":""},{"name":"Finland","alpha-2":"FI","alpha-3":"FIN","country-code":"246","iso_3166-2":"ISO 3166-2:FI","region":"Europe","sub-region":"Northern Europe","intermediate-region":"","region-code":"150","sub-region-code":"154","intermediate-region-code":""},{"name":"France","alpha-2":"FR","alpha-3":"FRA","country-code":"250","iso_3166-2":"ISO 3166-2:FR","region":"Europe","sub-region":"Western Europe","intermediate-region":"","region-code":"150","sub-region-code":"155","intermediate-region-code":""},{"name":"French Guiana","alpha-2":"GF","alpha-3":"GUF","country-code":"254","iso_3166-2":"ISO 3166-2:GF","region":"Americas","sub-region":"Latin America and the Caribbean","intermediate-region":"South America","region-code":"019","sub-region-code":"419","intermediate-region-code":"005"},{"name":"French Polynesia","alpha-2":"PF","alpha-3":"PYF","country-code":"258","iso_3166-2":"ISO 3166-2:PF","region":"Oceania","sub-region":"Polynesia","intermediate-region":"","region-code":"009","sub-region-code":"061","intermediate-region-code":""},{"name":"French Southern Territories","alpha-2":"TF","alpha-3":"ATF","country-code":"260","iso_3166-2":"ISO 3166-2:TF","region":"Africa","sub-region":"Sub-Saharan Africa","intermediate-region":"Eastern Africa","region-code":"002","sub-region-code":"202","intermediate-region-code":"014"},{"name":"Gabon","alpha-2":"GA","alpha-3":"GAB","country-code":"266","iso_3166-2":"ISO 3166-2:GA","region":"Africa","sub-region":"Sub-Saharan Africa","intermediate-region":"Middle Africa","region-code":"002","sub-region-code":"202","intermediate-region-code":"017"},{"name":"Gambia","alpha-2":"GM","alpha-3":"GMB","country-code":"270","iso_3166-2":"ISO 3166-2:GM","region":"Africa","sub-region":"Sub-Saharan Africa","intermediate-region":"Western Africa","region-code":"002","sub-region-code":"202","intermediate-region-code":"011"},{"name":"Georgia","alpha-2":"GE","alpha-3":"GEO","country-code":"268","iso_3166-2":"ISO 3166-2:GE","region":"Asia","sub-region":"Western Asia","intermediate-region":"","region-code":"142","sub-region-code":"145","intermediate-region-code":""},{"name":"Germany","alpha-2":"DE","alpha-3":"DEU","country-code":"276","iso_3166-2":"ISO 3166-2:DE","region":"Europe","sub-region":"Western Europe","intermediate-region":"","region-code":"150","sub-region-code":"155","intermediate-region-code":""},{"name":"Ghana","alpha-2":"GH","alpha-3":"GHA","country-code":"288","iso_3166-2":"ISO 3166-2:GH","region":"Africa","sub-region":"Sub-Saharan Africa","intermediate-region":"Western Africa","region-code":"002","sub-region-code":"202","intermediate-region-code":"011"},{"name":"Gibraltar","alpha-2":"GI","alpha-3":"GIB","country-code":"292","iso_3166-2":"ISO 3166-2:GI","region":"Europe","sub-region":"Southern Europe","intermediate-region":"","region-code":"150","sub-region-code":"039","intermediate-region-code":""},{"name":"Greece","alpha-2":"GR","alpha-3":"GRC","country-code":"300","iso_3166-2":"ISO 3166-2:GR","region":"Europe","sub-region":"Southern Europe","intermediate-region":"","region-code":"150","sub-region-code":"039","intermediate-region-code":""},{"name":"Greenland","alpha-2":"GL","alpha-3":"GRL","country-code":"304","iso_3166-2":"ISO 3166-2:GL","region":"Americas","sub-region":"Northern America","intermediate-region":"","region-code":"019","sub-region-code":"021","intermediate-region-code":""},{"name":"Grenada","alpha-2":"GD","alpha-3":"GRD","country-code":"308","iso_3166-2":"ISO 3166-2:GD","region":"Americas","sub-region":"Latin America and the Caribbean","intermediate-region":"Caribbean","region-code":"019","sub-region-code":"419","intermediate-region-code":"029"},{"name":"Guadeloupe","alpha-2":"GP","alpha-3":"GLP","country-code":"312","iso_3166-2":"ISO 3166-2:GP","region":"Americas","sub-region":"Latin America and the Caribbean","intermediate-region":"Caribbean","region-code":"019","sub-region-code":"419","intermediate-region-code":"029"},{"name":"Guam","alpha-2":"GU","alpha-3":"GUM","country-code":"316","iso_3166-2":"ISO 3166-2:GU","region":"Oceania","sub-region":"Micronesia","intermediate-region":"","region-code":"009","sub-region-code":"057","intermediate-region-code":""},{"name":"Guatemala","alpha-2":"GT","alpha-3":"GTM","country-code":"320","iso_3166-2":"ISO 3166-2:GT","region":"Americas","sub-region":"Latin America and the Caribbean","intermediate-region":"Central America","region-code":"019","sub-region-code":"419","intermediate-region-code":"013"},{"name":"Guernsey","alpha-2":"GG","alpha-3":"GGY","country-code":"831","iso_3166-2":"ISO 3166-2:GG","region":"Europe","sub-region":"Northern Europe","intermediate-region":"Channel Islands","region-code":"150","sub-region-code":"154","intermediate-region-code":"830"},{"name":"Guinea","alpha-2":"GN","alpha-3":"GIN","country-code":"324","iso_3166-2":"ISO 3166-2:GN","region":"Africa","sub-region":"Sub-Saharan Africa","intermediate-region":"Western Africa","region-code":"002","sub-region-code":"202","intermediate-region-code":"011"},{"name":"Guinea-Bissau","alpha-2":"GW","alpha-3":"GNB","country-code":"624","iso_3166-2":"ISO 3166-2:GW","region":"Africa","sub-region":"Sub-Saharan Africa","intermediate-region":"Western Africa","region-code":"002","sub-region-code":"202","intermediate-region-code":"011"},{"name":"Guyana","alpha-2":"GY","alpha-3":"GUY","country-code":"328","iso_3166-2":"ISO 3166-2:GY","region":"Americas","sub-region":"Latin America and the Caribbean","intermediate-region":"South America","region-code":"019","sub-region-code":"419","intermediate-region-code":"005"},{"name":"Haiti","alpha-2":"HT","alpha-3":"HTI","country-code":"332","iso_3166-2":"ISO 3166-2:HT","region":"Americas","sub-region":"Latin America and the Caribbean","intermediate-region":"Caribbean","region-code":"019","sub-region-code":"419","intermediate-region-code":"029"},{"name":"Heard Island and McDonald Islands","alpha-2":"HM","alpha-3":"HMD","country-code":"334","iso_3166-2":"ISO 3166-2:HM","region":"Oceania","sub-region":"Australia and New Zealand","intermediate-region":"","region-code":"009","sub-region-code":"053","intermediate-region-code":""},{"name":"Holy See","alpha-2":"VA","alpha-3":"VAT","country-code":"336","iso_3166-2":"ISO 3166-2:VA","region":"Europe","sub-region":"Southern Europe","intermediate-region":"","region-code":"150","sub-region-code":"039","intermediate-region-code":""},{"name":"Honduras","alpha-2":"HN","alpha-3":"HND","country-code":"340","iso_3166-2":"ISO 3166-2:HN","region":"Americas","sub-region":"Latin America and the Caribbean","intermediate-region":"Central America","region-code":"019","sub-region-code":"419","intermediate-region-code":"013"},{"name":"Hong Kong","alpha-2":"HK","alpha-3":"HKG","country-code":"344","iso_3166-2":"ISO 3166-2:HK","region":"Asia","sub-region":"Eastern Asia","intermediate-region":"","region-code":"142","sub-region-code":"030","intermediate-region-code":""},{"name":"Hungary","alpha-2":"HU","alpha-3":"HUN","country-code":"348","iso_3166-2":"ISO 3166-2:HU","region":"Europe","sub-region":"Eastern Europe","intermediate-region":"","region-code":"150","sub-region-code":"151","intermediate-region-code":""},{"name":"Iceland","alpha-2":"IS","alpha-3":"ISL","country-code":"352","iso_3166-2":"ISO 3166-2:IS","region":"Europe","sub-region":"Northern Europe","intermediate-region":"","region-code":"150","sub-region-code":"154","intermediate-region-code":""},{"name":"India","alpha-2":"IN","alpha-3":"IND","country-code":"356","iso_3166-2":"ISO 3166-2:IN","region":"Asia","sub-region":"Southern Asia","intermediate-region":"","region-code":"142","sub-region-code":"034","intermediate-region-code":""},{"name":"Indonesia","alpha-2":"ID","alpha-3":"IDN","country-code":"360","iso_3166-2":"ISO 3166-2:ID","region":"Asia","sub-region":"South-eastern Asia","intermediate-region":"","region-code":"142","sub-region-code":"035","intermediate-region-code":""},{"name":"Iran (Islamic Republic of)","alpha-2":"IR","alpha-3":"IRN","country-code":"364","iso_3166-2":"ISO 3166-2:IR","region":"Asia","sub-region":"Southern Asia","intermediate-region":"","region-code":"142","sub-region-code":"034","intermediate-region-code":""},{"name":"Iraq","alpha-2":"IQ","alpha-3":"IRQ","country-code":"368","iso_3166-2":"ISO 3166-2:IQ","region":"Asia","sub-region":"Western Asia","intermediate-region":"","region-code":"142","sub-region-code":"145","intermediate-region-code":""},{"name":"Ireland","alpha-2":"IE","alpha-3":"IRL","country-code":"372","iso_3166-2":"ISO 3166-2:IE","region":"Europe","sub-region":"Northern Europe","intermediate-region":"","region-code":"150","sub-region-code":"154","intermediate-region-code":""},{"name":"Isle of Man","alpha-2":"IM","alpha-3":"IMN","country-code":"833","iso_3166-2":"ISO 3166-2:IM","region":"Europe","sub-region":"Northern Europe","intermediate-region":"","region-code":"150","sub-region-code":"154","intermediate-region-code":""},{"name":"Israel","alpha-2":"IL","alpha-3":"ISR","country-code":"376","iso_3166-2":"ISO 3166-2:IL","region":"Asia","sub-region":"Western Asia","intermediate-region":"","region-code":"142","sub-region-code":"145","intermediate-region-code":""},{"name":"Italy","alpha-2":"IT","alpha-3":"ITA","country-code":"380","iso_3166-2":"ISO 3166-2:IT","region":"Europe","sub-region":"Southern Europe","intermediate-region":"","region-code":"150","sub-region-code":"039","intermediate-region-code":""},{"name":"Jamaica","alpha-2":"JM","alpha-3":"JAM","country-code":"388","iso_3166-2":"ISO 3166-2:JM","region":"Americas","sub-region":"Latin America and the Caribbean","intermediate-region":"Caribbean","region-code":"019","sub-region-code":"419","intermediate-region-code":"029"},{"name":"Japan","alpha-2":"JP","alpha-3":"JPN","country-code":"392","iso_3166-2":"ISO 3166-2:JP","region":"Asia","sub-region":"Eastern Asia","intermediate-region":"","region-code":"142","sub-region-code":"030","intermediate-region-code":""},{"name":"Jersey","alpha-2":"JE","alpha-3":"JEY","country-code":"832","iso_3166-2":"ISO 3166-2:JE","region":"Europe","sub-region":"Northern Europe","intermediate-region":"Channel Islands","region-code":"150","sub-region-code":"154","intermediate-region-code":"830"},{"name":"Jordan","alpha-2":"JO","alpha-3":"JOR","country-code":"400","iso_3166-2":"ISO 3166-2:JO","region":"Asia","sub-region":"Western Asia","intermediate-region":"","region-code":"142","sub-region-code":"145","intermediate-region-code":""},{"name":"Kazakhstan","alpha-2":"KZ","alpha-3":"KAZ","country-code":"398","iso_3166-2":"ISO 3166-2:KZ","region":"Asia","sub-region":"Central Asia","intermediate-region":"","region-code":"142","sub-region-code":"143","intermediate-region-code":""},{"name":"Kenya","alpha-2":"KE","alpha-3":"KEN","country-code":"404","iso_3166-2":"ISO 3166-2:KE","region":"Africa","sub-region":"Sub-Saharan Africa","intermediate-region":"Eastern Africa","region-code":"002","sub-region-code":"202","intermediate-region-code":"014"},{"name":"Kiribati","alpha-2":"KI","alpha-3":"KIR","country-code":"296","iso_3166-2":"ISO 3166-2:KI","region":"Oceania","sub-region":"Micronesia","intermediate-region":"","region-code":"009","sub-region-code":"057","intermediate-region-code":""},{"name":"Korea (Democratic People's Republic of)","alpha-2":"KP","alpha-3":"PRK","country-code":"408","iso_3166-2":"ISO 3166-2:KP","region":"Asia","sub-region":"Eastern Asia","intermediate-region":"","region-code":"142","sub-region-code":"030","intermediate-region-code":""},{"name":"Korea, Republic of","alpha-2":"KR","alpha-3":"KOR","country-code":"410","iso_3166-2":"ISO 3166-2:KR","region":"Asia","sub-region":"Eastern Asia","intermediate-region":"","region-code":"142","sub-region-code":"030","intermediate-region-code":""},{"name":"Kuwait","alpha-2":"KW","alpha-3":"KWT","country-code":"414","iso_3166-2":"ISO 3166-2:KW","region":"Asia","sub-region":"Western Asia","intermediate-region":"","region-code":"142","sub-region-code":"145","intermediate-region-code":""},{"name":"Kyrgyzstan","alpha-2":"KG","alpha-3":"KGZ","country-code":"417","iso_3166-2":"ISO 3166-2:KG","region":"Asia","sub-region":"Central Asia","intermediate-region":"","region-code":"142","sub-region-code":"143","intermediate-region-code":""},{"name":"Lao People's Democratic Republic","alpha-2":"LA","alpha-3":"LAO","country-code":"418","iso_3166-2":"ISO 3166-2:LA","region":"Asia","sub-region":"South-eastern Asia","intermediate-region":"","region-code":"142","sub-region-code":"035","intermediate-region-code":""},{"name":"Latvia","alpha-2":"LV","alpha-3":"LVA","country-code":"428","iso_3166-2":"ISO 3166-2:LV","region":"Europe","sub-region":"Northern Europe","intermediate-region":"","region-code":"150","sub-region-code":"154","intermediate-region-code":""},{"name":"Lebanon","alpha-2":"LB","alpha-3":"LBN","country-code":"422","iso_3166-2":"ISO 3166-2:LB","region":"Asia","sub-region":"Western Asia","intermediate-region":"","region-code":"142","sub-region-code":"145","intermediate-region-code":""},{"name":"Lesotho","alpha-2":"LS","alpha-3":"LSO","country-code":"426","iso_3166-2":"ISO 3166-2:LS","region":"Africa","sub-region":"Sub-Saharan Africa","intermediate-region":"Southern Africa","region-code":"002","sub-region-code":"202","intermediate-region-code":"018"},{"name":"Liberia","alpha-2":"LR","alpha-3":"LBR","country-code":"430","iso_3166-2":"ISO 3166-2:LR","region":"Africa","sub-region":"Sub-Saharan Africa","intermediate-region":"Western Africa","region-code":"002","sub-region-code":"202","intermediate-region-code":"011"},{"name":"Libya","alpha-2":"LY","alpha-3":"LBY","country-code":"434","iso_3166-2":"ISO 3166-2:LY","region":"Africa","sub-region":"Northern Africa","intermediate-region":"","region-code":"002","sub-region-code":"015","intermediate-region-code":""},{"name":"Liechtenstein","alpha-2":"LI","alpha-3":"LIE","country-code":"438","iso_3166-2":"ISO 3166-2:LI","region":"Europe","sub-region":"Western Europe","intermediate-region":"","region-code":"150","sub-region-code":"155","intermediate-region-code":""},{"name":"Lithuania","alpha-2":"LT","alpha-3":"LTU","country-code":"440","iso_3166-2":"ISO 3166-2:LT","region":"Europe","sub-region":"Northern Europe","intermediate-region":"","region-code":"150","sub-region-code":"154","intermediate-region-code":""},{"name":"Luxembourg","alpha-2":"LU","alpha-3":"LUX","country-code":"442","iso_3166-2":"ISO 3166-2:LU","region":"Europe","sub-region":"Western Europe","intermediate-region":"","region-code":"150","sub-region-code":"155","intermediate-region-code":""},{"name":"Macao","alpha-2":"MO","alpha-3":"MAC","country-code":"446","iso_3166-2":"ISO 3166-2:MO","region":"Asia","sub-region":"Eastern Asia","intermediate-region":"","region-code":"142","sub-region-code":"030","intermediate-region-code":""},{"name":"Madagascar","alpha-2":"MG","alpha-3":"MDG","country-code":"450","iso_3166-2":"ISO 3166-2:MG","region":"Africa","sub-region":"Sub-Saharan Africa","intermediate-region":"Eastern Africa","region-code":"002","sub-region-code":"202","intermediate-region-code":"014"},{"name":"Malawi","alpha-2":"MW","alpha-3":"MWI","country-code":"454","iso_3166-2":"ISO 3166-2:MW","region":"Africa","sub-region":"Sub-Saharan Africa","intermediate-region":"Eastern Africa","region-code":"002","sub-region-code":"202","intermediate-region-code":"014"},{"name":"Malaysia","alpha-2":"MY","alpha-3":"MYS","country-code":"458","iso_3166-2":"ISO 3166-2:MY","region":"Asia","sub-region":"South-eastern Asia","intermediate-region":"","region-code":"142","sub-region-code":"035","intermediate-region-code":""},{"name":"Maldives","alpha-2":"MV","alpha-3":"MDV","country-code":"462","iso_3166-2":"ISO 3166-2:MV","region":"Asia","sub-region":"Southern Asia","intermediate-region":"","region-code":"142","sub-region-code":"034","intermediate-region-code":""},{"name":"Mali","alpha-2":"ML","alpha-3":"MLI","country-code":"466","iso_3166-2":"ISO 3166-2:ML","region":"Africa","sub-region":"Sub-Saharan Africa","intermediate-region":"Western Africa","region-code":"002","sub-region-code":"202","intermediate-region-code":"011"},{"name":"Malta","alpha-2":"MT","alpha-3":"MLT","country-code":"470","iso_3166-2":"ISO 3166-2:MT","region":"Europe","sub-region":"Southern Europe","intermediate-region":"","region-code":"150","sub-region-code":"039","intermediate-region-code":""},{"name":"Marshall Islands","alpha-2":"MH","alpha-3":"MHL","country-code":"584","iso_3166-2":"ISO 3166-2:MH","region":"Oceania","sub-region":"Micronesia","intermediate-region":"","region-code":"009","sub-region-code":"057","intermediate-region-code":""},{"name":"Martinique","alpha-2":"MQ","alpha-3":"MTQ","country-code":"474","iso_3166-2":"ISO 3166-2:MQ","region":"Americas","sub-region":"Latin America and the Caribbean","intermediate-region":"Caribbean","region-code":"019","sub-region-code":"419","intermediate-region-code":"029"},{"name":"Mauritania","alpha-2":"MR","alpha-3":"MRT","country-code":"478","iso_3166-2":"ISO 3166-2:MR","region":"Africa","sub-region":"Sub-Saharan Africa","intermediate-region":"Western Africa","region-code":"002","sub-region-code":"202","intermediate-region-code":"011"},{"name":"Mauritius","alpha-2":"MU","alpha-3":"MUS","country-code":"480","iso_3166-2":"ISO 3166-2:MU","region":"Africa","sub-region":"Sub-Saharan Africa","intermediate-region":"Eastern Africa","region-code":"002","sub-region-code":"202","intermediate-region-code":"014"},{"name":"Mayotte","alpha-2":"YT","alpha-3":"MYT","country-code":"175","iso_3166-2":"ISO 3166-2:YT","region":"Africa","sub-region":"Sub-Saharan Africa","intermediate-region":"Eastern Africa","region-code":"002","sub-region-code":"202","intermediate-region-code":"014"},{"name":"Mexico","alpha-2":"MX","alpha-3":"MEX","country-code":"484","iso_3166-2":"ISO 3166-2:MX","region":"Americas","sub-region":"Latin America and the Caribbean","intermediate-region":"Central America","region-code":"019","sub-region-code":"419","intermediate-region-code":"013"},{"name":"Micronesia (Federated States of)","alpha-2":"FM","alpha-3":"FSM","country-code":"583","iso_3166-2":"ISO 3166-2:FM","region":"Oceania","sub-region":"Micronesia","intermediate-region":"","region-code":"009","sub-region-code":"057","intermediate-region-code":""},{"name":"Moldova, Republic of","alpha-2":"MD","alpha-3":"MDA","country-code":"498","iso_3166-2":"ISO 3166-2:MD","region":"Europe","sub-region":"Eastern Europe","intermediate-region":"","region-code":"150","sub-region-code":"151","intermediate-region-code":""},{"name":"Monaco","alpha-2":"MC","alpha-3":"MCO","country-code":"492","iso_3166-2":"ISO 3166-2:MC","region":"Europe","sub-region":"Western Europe","intermediate-region":"","region-code":"150","sub-region-code":"155","intermediate-region-code":""},{"name":"Mongolia","alpha-2":"MN","alpha-3":"MNG","country-code":"496","iso_3166-2":"ISO 3166-2:MN","region":"Asia","sub-region":"Eastern Asia","intermediate-region":"","region-code":"142","sub-region-code":"030","intermediate-region-code":""},{"name":"Montenegro","alpha-2":"ME","alpha-3":"MNE","country-code":"499","iso_3166-2":"ISO 3166-2:ME","region":"Europe","sub-region":"Southern Europe","intermediate-region":"","region-code":"150","sub-region-code":"039","intermediate-region-code":""},{"name":"Montserrat","alpha-2":"MS","alpha-3":"MSR","country-code":"500","iso_3166-2":"ISO 3166-2:MS","region":"Americas","sub-region":"Latin America and the Caribbean","intermediate-region":"Caribbean","region-code":"019","sub-region-code":"419","intermediate-region-code":"029"},{"name":"Morocco","alpha-2":"MA","alpha-3":"MAR","country-code":"504","iso_3166-2":"ISO 3166-2:MA","region":"Africa","sub-region":"Northern Africa","intermediate-region":"","region-code":"002","sub-region-code":"015","intermediate-region-code":""},{"name":"Mozambique","alpha-2":"MZ","alpha-3":"MOZ","country-code":"508","iso_3166-2":"ISO 3166-2:MZ","region":"Africa","sub-region":"Sub-Saharan Africa","intermediate-region":"Eastern Africa","region-code":"002","sub-region-code":"202","intermediate-region-code":"014"},{"name":"Myanmar","alpha-2":"MM","alpha-3":"MMR","country-code":"104","iso_3166-2":"ISO 3166-2:MM","region":"Asia","sub-region":"South-eastern Asia","intermediate-region":"","region-code":"142","sub-region-code":"035","intermediate-region-code":""},{"name":"Namibia","alpha-2":"NA","alpha-3":"NAM","country-code":"516","iso_3166-2":"ISO 3166-2:NA","region":"Africa","sub-region":"Sub-Saharan Africa","intermediate-region":"Southern Africa","region-code":"002","sub-region-code":"202","intermediate-region-code":"018"},{"name":"Nauru","alpha-2":"NR","alpha-3":"NRU","country-code":"520","iso_3166-2":"ISO 3166-2:NR","region":"Oceania","sub-region":"Micronesia","intermediate-region":"","region-code":"009","sub-region-code":"057","intermediate-region-code":""},{"name":"Nepal","alpha-2":"NP","alpha-3":"NPL","country-code":"524","iso_3166-2":"ISO 3166-2:NP","region":"Asia","sub-region":"Southern Asia","intermediate-region":"","region-code":"142","sub-region-code":"034","intermediate-region-code":""},{"name":"Netherlands","alpha-2":"NL","alpha-3":"NLD","country-code":"528","iso_3166-2":"ISO 3166-2:NL","region":"Europe","sub-region":"Western Europe","intermediate-region":"","region-code":"150","sub-region-code":"155","intermediate-region-code":""},{"name":"New Caledonia","alpha-2":"NC","alpha-3":"NCL","country-code":"540","iso_3166-2":"ISO 3166-2:NC","region":"Oceania","sub-region":"Melanesia","intermediate-region":"","region-code":"009","sub-region-code":"054","intermediate-region-code":""},{"name":"New Zealand","alpha-2":"NZ","alpha-3":"NZL","country-code":"554","iso_3166-2":"ISO 3166-2:NZ","region":"Oceania","sub-region":"Australia and New Zealand","intermediate-region":"","region-code":"009","sub-region-code":"053","intermediate-region-code":""},{"name":"Nicaragua","alpha-2":"NI","alpha-3":"NIC","country-code":"558","iso_3166-2":"ISO 3166-2:NI","region":"Americas","sub-region":"Latin America and the Caribbean","intermediate-region":"Central America","region-code":"019","sub-region-code":"419","intermediate-region-code":"013"},{"name":"Niger","alpha-2":"NE","alpha-3":"NER","country-code":"562","iso_3166-2":"ISO 3166-2:NE","region":"Africa","sub-region":"Sub-Saharan Africa","intermediate-region":"Western Africa","region-code":"002","sub-region-code":"202","intermediate-region-code":"011"},{"name":"Nigeria","alpha-2":"NG","alpha-3":"NGA","country-code":"566","iso_3166-2":"ISO 3166-2:NG","region":"Africa","sub-region":"Sub-Saharan Africa","intermediate-region":"Western Africa","region-code":"002","sub-region-code":"202","intermediate-region-code":"011"},{"name":"Niue","alpha-2":"NU","alpha-3":"NIU","country-code":"570","iso_3166-2":"ISO 3166-2:NU","region":"Oceania","sub-region":"Polynesia","intermediate-region":"","region-code":"009","sub-region-code":"061","intermediate-region-code":""},{"name":"Norfolk Island","alpha-2":"NF","alpha-3":"NFK","country-code":"574","iso_3166-2":"ISO 3166-2:NF","region":"Oceania","sub-region":"Australia and New Zealand","intermediate-region":"","region-code":"009","sub-region-code":"053","intermediate-region-code":""},{"name":"North Macedonia","alpha-2":"MK","alpha-3":"MKD","country-code":"807","iso_3166-2":"ISO 3166-2:MK","region":"Europe","sub-region":"Southern Europe","intermediate-region":"","region-code":"150","sub-region-code":"039","intermediate-region-code":""},{"name":"Northern Mariana Islands","alpha-2":"MP","alpha-3":"MNP","country-code":"580","iso_3166-2":"ISO 3166-2:MP","region":"Oceania","sub-region":"Micronesia","intermediate-region":"","region-code":"009","sub-region-code":"057","intermediate-region-code":""},{"name":"Norway","alpha-2":"NO","alpha-3":"NOR","country-code":"578","iso_3166-2":"ISO 3166-2:NO","region":"Europe","sub-region":"Northern Europe","intermediate-region":"","region-code":"150","sub-region-code":"154","intermediate-region-code":""},{"name":"Oman","alpha-2":"OM","alpha-3":"OMN","country-code":"512","iso_3166-2":"ISO 3166-2:OM","region":"Asia","sub-region":"Western Asia","intermediate-region":"","region-code":"142","sub-region-code":"145","intermediate-region-code":""},{"name":"Pakistan","alpha-2":"PK","alpha-3":"PAK","country-code":"586","iso_3166-2":"ISO 3166-2:PK","region":"Asia","sub-region":"Southern Asia","intermediate-region":"","region-code":"142","sub-region-code":"034","intermediate-region-code":""},{"name":"Palau","alpha-2":"PW","alpha-3":"PLW","country-code":"585","iso_3166-2":"ISO 3166-2:PW","region":"Oceania","sub-region":"Micronesia","intermediate-region":"","region-code":"009","sub-region-code":"057","intermediate-region-code":""},{"name":"Palestine, State of","alpha-2":"PS","alpha-3":"PSE","country-code":"275","iso_3166-2":"ISO 3166-2:PS","region":"Asia","sub-region":"Western Asia","intermediate-region":"","region-code":"142","sub-region-code":"145","intermediate-region-code":""},{"name":"Panama","alpha-2":"PA","alpha-3":"PAN","country-code":"591","iso_3166-2":"ISO 3166-2:PA","region":"Americas","sub-region":"Latin America and the Caribbean","intermediate-region":"Central America","region-code":"019","sub-region-code":"419","intermediate-region-code":"013"},{"name":"Papua New Guinea","alpha-2":"PG","alpha-3":"PNG","country-code":"598","iso_3166-2":"ISO 3166-2:PG","region":"Oceania","sub-region":"Melanesia","intermediate-region":"","region-code":"009","sub-region-code":"054","intermediate-region-code":""},{"name":"Paraguay","alpha-2":"PY","alpha-3":"PRY","country-code":"600","iso_3166-2":"ISO 3166-2:PY","region":"Americas","sub-region":"Latin America and the Caribbean","intermediate-region":"South America","region-code":"019","sub-region-code":"419","intermediate-region-code":"005"},{"name":"Peru","alpha-2":"PE","alpha-3":"PER","country-code":"604","iso_3166-2":"ISO 3166-2:PE","region":"Americas","sub-region":"Latin America and the Caribbean","intermediate-region":"South America","region-code":"019","sub-region-code":"419","intermediate-region-code":"005"},{"name":"Philippines","alpha-2":"PH","alpha-3":"PHL","country-code":"608","iso_3166-2":"ISO 3166-2:PH","region":"Asia","sub-region":"South-eastern Asia","intermediate-region":"","region-code":"142","sub-region-code":"035","intermediate-region-code":""},{"name":"Pitcairn","alpha-2":"PN","alpha-3":"PCN","country-code":"612","iso_3166-2":"ISO 3166-2:PN","region":"Oceania","sub-region":"Polynesia","intermediate-region":"","region-code":"009","sub-region-code":"061","intermediate-region-code":""},{"name":"Poland","alpha-2":"PL","alpha-3":"POL","country-code":"616","iso_3166-2":"ISO 3166-2:PL","region":"Europe","sub-region":"Eastern Europe","intermediate-region":"","region-code":"150","sub-region-code":"151","intermediate-region-code":""},{"name":"Portugal","alpha-2":"PT","alpha-3":"PRT","country-code":"620","iso_3166-2":"ISO 3166-2:PT","region":"Europe","sub-region":"Southern Europe","intermediate-region":"","region-code":"150","sub-region-code":"039","intermediate-region-code":""},{"name":"Puerto Rico","alpha-2":"PR","alpha-3":"PRI","country-code":"630","iso_3166-2":"ISO 3166-2:PR","region":"Americas","sub-region":"Latin America and the Caribbean","intermediate-region":"Caribbean","region-code":"019","sub-region-code":"419","intermediate-region-code":"029"},{"name":"Qatar","alpha-2":"QA","alpha-3":"QAT","country-code":"634","iso_3166-2":"ISO 3166-2:QA","region":"Asia","sub-region":"Western Asia","intermediate-region":"","region-code":"142","sub-region-code":"145","intermediate-region-code":""},{"name":"Réunion","alpha-2":"RE","alpha-3":"REU","country-code":"638","iso_3166-2":"ISO 3166-2:RE","region":"Africa","sub-region":"Sub-Saharan Africa","intermediate-region":"Eastern Africa","region-code":"002","sub-region-code":"202","intermediate-region-code":"014"},{"name":"Romania","alpha-2":"RO","alpha-3":"ROU","country-code":"642","iso_3166-2":"ISO 3166-2:RO","region":"Europe","sub-region":"Eastern Europe","intermediate-region":"","region-code":"150","sub-region-code":"151","intermediate-region-code":""},{"name":"Russian Federation","alpha-2":"RU","alpha-3":"RUS","country-code":"643","iso_3166-2":"ISO 3166-2:RU","region":"Europe","sub-region":"Eastern Europe","intermediate-region":"","region-code":"150","sub-region-code":"151","intermediate-region-code":""},{"name":"Rwanda","alpha-2":"RW","alpha-3":"RWA","country-code":"646","iso_3166-2":"ISO 3166-2:RW","region":"Africa","sub-region":"Sub-Saharan Africa","intermediate-region":"Eastern Africa","region-code":"002","sub-region-code":"202","intermediate-region-code":"014"},{"name":"Saint Barthélemy","alpha-2":"BL","alpha-3":"BLM","country-code":"652","iso_3166-2":"ISO 3166-2:BL","region":"Americas","sub-region":"Latin America and the Caribbean","intermediate-region":"Caribbean","region-code":"019","sub-region-code":"419","intermediate-region-code":"029"},{"name":"Saint Helena, Ascension and Tristan da Cunha","alpha-2":"SH","alpha-3":"SHN","country-code":"654","iso_3166-2":"ISO 3166-2:SH","region":"Africa","sub-region":"Sub-Saharan Africa","intermediate-region":"Western Africa","region-code":"002","sub-region-code":"202","intermediate-region-code":"011"},{"name":"Saint Kitts and Nevis","alpha-2":"KN","alpha-3":"KNA","country-code":"659","iso_3166-2":"ISO 3166-2:KN","region":"Americas","sub-region":"Latin America and the Caribbean","intermediate-region":"Caribbean","region-code":"019","sub-region-code":"419","intermediate-region-code":"029"},{"name":"Saint Lucia","alpha-2":"LC","alpha-3":"LCA","country-code":"662","iso_3166-2":"ISO 3166-2:LC","region":"Americas","sub-region":"Latin America and the Caribbean","intermediate-region":"Caribbean","region-code":"019","sub-region-code":"419","intermediate-region-code":"029"},{"name":"Saint Martin (French part)","alpha-2":"MF","alpha-3":"MAF","country-code":"663","iso_3166-2":"ISO 3166-2:MF","region":"Americas","sub-region":"Latin America and the Caribbean","intermediate-region":"Caribbean","region-code":"019","sub-region-code":"419","intermediate-region-code":"029"},{"name":"Saint Pierre and Miquelon","alpha-2":"PM","alpha-3":"SPM","country-code":"666","iso_3166-2":"ISO 3166-2:PM","region":"Americas","sub-region":"Northern America","intermediate-region":"","region-code":"019","sub-region-code":"021","intermediate-region-code":""},{"name":"Saint Vincent and the Grenadines","alpha-2":"VC","alpha-3":"VCT","country-code":"670","iso_3166-2":"ISO 3166-2:VC","region":"Americas","sub-region":"Latin America and the Caribbean","intermediate-region":"Caribbean","region-code":"019","sub-region-code":"419","intermediate-region-code":"029"},{"name":"Samoa","alpha-2":"WS","alpha-3":"WSM","country-code":"882","iso_3166-2":"ISO 3166-2:WS","region":"Oceania","sub-region":"Polynesia","intermediate-region":"","region-code":"009","sub-region-code":"061","intermediate-region-code":""},{"name":"San Marino","alpha-2":"SM","alpha-3":"SMR","country-code":"674","iso_3166-2":"ISO 3166-2:SM","region":"Europe","sub-region":"Southern Europe","intermediate-region":"","region-code":"150","sub-region-code":"039","intermediate-region-code":""},{"name":"Sao Tome and Principe","alpha-2":"ST","alpha-3":"STP","country-code":"678","iso_3166-2":"ISO 3166-2:ST","region":"Africa","sub-region":"Sub-Saharan Africa","intermediate-region":"Middle Africa","region-code":"002","sub-region-code":"202","intermediate-region-code":"017"},{"name":"Saudi Arabia","alpha-2":"SA","alpha-3":"SAU","country-code":"682","iso_3166-2":"ISO 3166-2:SA","region":"Asia","sub-region":"Western Asia","intermediate-region":"","region-code":"142","sub-region-code":"145","intermediate-region-code":""},{"name":"Senegal","alpha-2":"SN","alpha-3":"SEN","country-code":"686","iso_3166-2":"ISO 3166-2:SN","region":"Africa","sub-region":"Sub-Saharan Africa","intermediate-region":"Western Africa","region-code":"002","sub-region-code":"202","intermediate-region-code":"011"},{"name":"Serbia","alpha-2":"RS","alpha-3":"SRB","country-code":"688","iso_3166-2":"ISO 3166-2:RS","region":"Europe","sub-region":"Southern Europe","intermediate-region":"","region-code":"150","sub-region-code":"039","intermediate-region-code":""},{"name":"Seychelles","alpha-2":"SC","alpha-3":"SYC","country-code":"690","iso_3166-2":"ISO 3166-2:SC","region":"Africa","sub-region":"Sub-Saharan Africa","intermediate-region":"Eastern Africa","region-code":"002","sub-region-code":"202","intermediate-region-code":"014"},{"name":"Sierra Leone","alpha-2":"SL","alpha-3":"SLE","country-code":"694","iso_3166-2":"ISO 3166-2:SL","region":"Africa","sub-region":"Sub-Saharan Africa","intermediate-region":"Western Africa","region-code":"002","sub-region-code":"202","intermediate-region-code":"011"},{"name":"Singapore","alpha-2":"SG","alpha-3":"SGP","country-code":"702","iso_3166-2":"ISO 3166-2:SG","region":"Asia","sub-region":"South-eastern Asia","intermediate-region":"","region-code":"142","sub-region-code":"035","intermediate-region-code":""},{"name":"Sint Maarten (Dutch part)","alpha-2":"SX","alpha-3":"SXM","country-code":"534","iso_3166-2":"ISO 3166-2:SX","region":"Americas","sub-region":"Latin America and the Caribbean","intermediate-region":"Caribbean","region-code":"019","sub-region-code":"419","intermediate-region-code":"029"},{"name":"Slovakia","alpha-2":"SK","alpha-3":"SVK","country-code":"703","iso_3166-2":"ISO 3166-2:SK","region":"Europe","sub-region":"Eastern Europe","intermediate-region":"","region-code":"150","sub-region-code":"151","intermediate-region-code":""},{"name":"Slovenia","alpha-2":"SI","alpha-3":"SVN","country-code":"705","iso_3166-2":"ISO 3166-2:SI","region":"Europe","sub-region":"Southern Europe","intermediate-region":"","region-code":"150","sub-region-code":"039","intermediate-region-code":""},{"name":"Solomon Islands","alpha-2":"SB","alpha-3":"SLB","country-code":"090","iso_3166-2":"ISO 3166-2:SB","region":"Oceania","sub-region":"Melanesia","intermediate-region":"","region-code":"009","sub-region-code":"054","intermediate-region-code":""},{"name":"Somalia","alpha-2":"SO","alpha-3":"SOM","country-code":"706","iso_3166-2":"ISO 3166-2:SO","region":"Africa","sub-region":"Sub-Saharan Africa","intermediate-region":"Eastern Africa","region-code":"002","sub-region-code":"202","intermediate-region-code":"014"},{"name":"South Africa","alpha-2":"ZA","alpha-3":"ZAF","country-code":"710","iso_3166-2":"ISO 3166-2:ZA","region":"Africa","sub-region":"Sub-Saharan Africa","intermediate-region":"Southern Africa","region-code":"002","sub-region-code":"202","intermediate-region-code":"018"},{"name":"South Georgia and the South Sandwich Islands","alpha-2":"GS","alpha-3":"SGS","country-code":"239","iso_3166-2":"ISO 3166-2:GS","region":"Americas","sub-region":"Latin America and the Caribbean","intermediate-region":"South America","region-code":"019","sub-region-code":"419","intermediate-region-code":"005"},{"name":"South Sudan","alpha-2":"SS","alpha-3":"SSD","country-code":"728","iso_3166-2":"ISO 3166-2:SS","region":"Africa","sub-region":"Sub-Saharan Africa","intermediate-region":"Eastern Africa","region-code":"002","sub-region-code":"202","intermediate-region-code":"014"},{"name":"Spain","alpha-2":"ES","alpha-3":"ESP","country-code":"724","iso_3166-2":"ISO 3166-2:ES","region":"Europe","sub-region":"Southern Europe","intermediate-region":"","region-code":"150","sub-region-code":"039","intermediate-region-code":""},{"name":"Sri Lanka","alpha-2":"LK","alpha-3":"LKA","country-code":"144","iso_3166-2":"ISO 3166-2:LK","region":"Asia","sub-region":"Southern Asia","intermediate-region":"","region-code":"142","sub-region-code":"034","intermediate-region-code":""},{"name":"Sudan","alpha-2":"SD","alpha-3":"SDN","country-code":"729","iso_3166-2":"ISO 3166-2:SD","region":"Africa","sub-region":"Northern Africa","intermediate-region":"","region-code":"002","sub-region-code":"015","intermediate-region-code":""},{"name":"Suriname","alpha-2":"SR","alpha-3":"SUR","country-code":"740","iso_3166-2":"ISO 3166-2:SR","region":"Americas","sub-region":"Latin America and the Caribbean","intermediate-region":"South America","region-code":"019","sub-region-code":"419","intermediate-region-code":"005"},{"name":"Svalbard and Jan Mayen","alpha-2":"SJ","alpha-3":"SJM","country-code":"744","iso_3166-2":"ISO 3166-2:SJ","region":"Europe","sub-region":"Northern Europe","intermediate-region":"","region-code":"150","sub-region-code":"154","intermediate-region-code":""},{"name":"Sweden","alpha-2":"SE","alpha-3":"SWE","country-code":"752","iso_3166-2":"ISO 3166-2:SE","region":"Europe","sub-region":"Northern Europe","intermediate-region":"","region-code":"150","sub-region-code":"154","intermediate-region-code":""},{"name":"Switzerland","alpha-2":"CH","alpha-3":"CHE","country-code":"756","iso_3166-2":"ISO 3166-2:CH","region":"Europe","sub-region":"Western Europe","intermediate-region":"","region-code":"150","sub-region-code":"155","intermediate-region-code":""},{"name":"Syrian Arab Republic","alpha-2":"SY","alpha-3":"SYR","country-code":"760","iso_3166-2":"ISO 3166-2:SY","region":"Asia","sub-region":"Western Asia","intermediate-region":"","region-code":"142","sub-region-code":"145","intermediate-region-code":""},{"name":"Taiwan, Province of China","alpha-2":"TW","alpha-3":"TWN","country-code":"158","iso_3166-2":"ISO 3166-2:TW","region":"Asia","sub-region":"Eastern Asia","intermediate-region":"","region-code":"142","sub-region-code":"030","intermediate-region-code":""},{"name":"Tajikistan","alpha-2":"TJ","alpha-3":"TJK","country-code":"762","iso_3166-2":"ISO 3166-2:TJ","region":"Asia","sub-region":"Central Asia","intermediate-region":"","region-code":"142","sub-region-code":"143","intermediate-region-code":""},{"name":"Tanzania, United Republic of","alpha-2":"TZ","alpha-3":"TZA","country-code":"834","iso_3166-2":"ISO 3166-2:TZ","region":"Africa","sub-region":"Sub-Saharan Africa","intermediate-region":"Eastern Africa","region-code":"002","sub-region-code":"202","intermediate-region-code":"014"},{"name":"Thailand","alpha-2":"TH","alpha-3":"THA","country-code":"764","iso_3166-2":"ISO 3166-2:TH","region":"Asia","sub-region":"South-eastern Asia","intermediate-region":"","region-code":"142","sub-region-code":"035","intermediate-region-code":""},{"name":"Timor-Leste","alpha-2":"TL","alpha-3":"TLS","country-code":"626","iso_3166-2":"ISO 3166-2:TL","region":"Asia","sub-region":"South-eastern Asia","intermediate-region":"","region-code":"142","sub-region-code":"035","intermediate-region-code":""},{"name":"Togo","alpha-2":"TG","alpha-3":"TGO","country-code":"768","iso_3166-2":"ISO 3166-2:TG","region":"Africa","sub-region":"Sub-Saharan Africa","intermediate-region":"Western Africa","region-code":"002","sub-region-code":"202","intermediate-region-code":"011"},{"name":"Tokelau","alpha-2":"TK","alpha-3":"TKL","country-code":"772","iso_3166-2":"ISO 3166-2:TK","region":"Oceania","sub-region":"Polynesia","intermediate-region":"","region-code":"009","sub-region-code":"061","intermediate-region-code":""},{"name":"Tonga","alpha-2":"TO","alpha-3":"TON","country-code":"776","iso_3166-2":"ISO 3166-2:TO","region":"Oceania","sub-region":"Polynesia","intermediate-region":"","region-code":"009","sub-region-code":"061","intermediate-region-code":""},{"name":"Trinidad and Tobago","alpha-2":"TT","alpha-3":"TTO","country-code":"780","iso_3166-2":"ISO 3166-2:TT","region":"Americas","sub-region":"Latin America and the Caribbean","intermediate-region":"Caribbean","region-code":"019","sub-region-code":"419","intermediate-region-code":"029"},{"name":"Tunisia","alpha-2":"TN","alpha-3":"TUN","country-code":"788","iso_3166-2":"ISO 3166-2:TN","region":"Africa","sub-region":"Northern Africa","intermediate-region":"","region-code":"002","sub-region-code":"015","intermediate-region-code":""},{"name":"Turkey","alpha-2":"TR","alpha-3":"TUR","country-code":"792","iso_3166-2":"ISO 3166-2:TR","region":"Asia","sub-region":"Western Asia","intermediate-region":"","region-code":"142","sub-region-code":"145","intermediate-region-code":""},{"name":"Turkmenistan","alpha-2":"TM","alpha-3":"TKM","country-code":"795","iso_3166-2":"ISO 3166-2:TM","region":"Asia","sub-region":"Central Asia","intermediate-region":"","region-code":"142","sub-region-code":"143","intermediate-region-code":""},{"name":"Turks and Caicos Islands","alpha-2":"TC","alpha-3":"TCA","country-code":"796","iso_3166-2":"ISO 3166-2:TC","region":"Americas","sub-region":"Latin America and the Caribbean","intermediate-region":"Caribbean","region-code":"019","sub-region-code":"419","intermediate-region-code":"029"},{"name":"Tuvalu","alpha-2":"TV","alpha-3":"TUV","country-code":"798","iso_3166-2":"ISO 3166-2:TV","region":"Oceania","sub-region":"Polynesia","intermediate-region":"","region-code":"009","sub-region-code":"061","intermediate-region-code":""},{"name":"Uganda","alpha-2":"UG","alpha-3":"UGA","country-code":"800","iso_3166-2":"ISO 3166-2:UG","region":"Africa","sub-region":"Sub-Saharan Africa","intermediate-region":"Eastern Africa","region-code":"002","sub-region-code":"202","intermediate-region-code":"014"},{"name":"Ukraine","alpha-2":"UA","alpha-3":"UKR","country-code":"804","iso_3166-2":"ISO 3166-2:UA","region":"Europe","sub-region":"Eastern Europe","intermediate-region":"","region-code":"150","sub-region-code":"151","intermediate-region-code":""},{"name":"United Arab Emirates","alpha-2":"AE","alpha-3":"ARE","country-code":"784","iso_3166-2":"ISO 3166-2:AE","region":"Asia","sub-region":"Western Asia","intermediate-region":"","region-code":"142","sub-region-code":"145","intermediate-region-code":""},{"name":"United Kingdom of Great Britain and Northern Ireland","alpha-2":"GB","alpha-3":"GBR","country-code":"826","iso_3166-2":"ISO 3166-2:GB","region":"Europe","sub-region":"Northern Europe","intermediate-region":"","region-code":"150","sub-region-code":"154","intermediate-region-code":""},{"name":"United States of America","alpha-2":"US","alpha-3":"USA","country-code":"840","iso_3166-2":"ISO 3166-2:US","region":"Americas","sub-region":"Northern America","intermediate-region":"","region-code":"019","sub-region-code":"021","intermediate-region-code":""},{"name":"United States Minor Outlying Islands","alpha-2":"UM","alpha-3":"UMI","country-code":"581","iso_3166-2":"ISO 3166-2:UM","region":"Oceania","sub-region":"Micronesia","intermediate-region":"","region-code":"009","sub-region-code":"057","intermediate-region-code":""},{"name":"Uruguay","alpha-2":"UY","alpha-3":"URY","country-code":"858","iso_3166-2":"ISO 3166-2:UY","region":"Americas","sub-region":"Latin America and the Caribbean","intermediate-region":"South America","region-code":"019","sub-region-code":"419","intermediate-region-code":"005"},{"name":"Uzbekistan","alpha-2":"UZ","alpha-3":"UZB","country-code":"860","iso_3166-2":"ISO 3166-2:UZ","region":"Asia","sub-region":"Central Asia","intermediate-region":"","region-code":"142","sub-region-code":"143","intermediate-region-code":""},{"name":"Vanuatu","alpha-2":"VU","alpha-3":"VUT","country-code":"548","iso_3166-2":"ISO 3166-2:VU","region":"Oceania","sub-region":"Melanesia","intermediate-region":"","region-code":"009","sub-region-code":"054","intermediate-region-code":""},{"name":"Venezuela (Bolivarian Republic of)","alpha-2":"VE","alpha-3":"VEN","country-code":"862","iso_3166-2":"ISO 3166-2:VE","region":"Americas","sub-region":"Latin America and the Caribbean","intermediate-region":"South America","region-code":"019","sub-region-code":"419","intermediate-region-code":"005"},{"name":"Viet Nam","alpha-2":"VN","alpha-3":"VNM","country-code":"704","iso_3166-2":"ISO 3166-2:VN","region":"Asia","sub-region":"South-eastern Asia","intermediate-region":"","region-code":"142","sub-region-code":"035","intermediate-region-code":""},{"name":"Virgin Islands (British)","alpha-2":"VG","alpha-3":"VGB","country-code":"092","iso_3166-2":"ISO 3166-2:VG","region":"Americas","sub-region":"Latin America and the Caribbean","intermediate-region":"Caribbean","region-code":"019","sub-region-code":"419","intermediate-region-code":"029"},{"name":"Virgin Islands (U.S.)","alpha-2":"VI","alpha-3":"VIR","country-code":"850","iso_3166-2":"ISO 3166-2:VI","region":"Americas","sub-region":"Latin America and the Caribbean","intermediate-region":"Caribbean","region-code":"019","sub-region-code":"419","intermediate-region-code":"029"},{"name":"Wallis and Futuna","alpha-2":"WF","alpha-3":"WLF","country-code":"876","iso_3166-2":"ISO 3166-2:WF","region":"Oceania","sub-region":"Polynesia","intermediate-region":"","region-code":"009","sub-region-code":"061","intermediate-region-code":""},{"name":"Western Sahara","alpha-2":"EH","alpha-3":"ESH","country-code":"732","iso_3166-2":"ISO 3166-2:EH","region":"Africa","sub-region":"Northern Africa","intermediate-region":"","region-code":"002","sub-region-code":"015","intermediate-region-code":""},{"name":"Yemen","alpha-2":"YE","alpha-3":"YEM","country-code":"887","iso_3166-2":"ISO 3166-2:YE","region":"Asia","sub-region":"Western Asia","intermediate-region":"","region-code":"142","sub-region-code":"145","intermediate-region-code":""},{"name":"Zambia","alpha-2":"ZM","alpha-3":"ZMB","country-code":"894","iso_3166-2":"ISO 3166-2:ZM","region":"Africa","sub-region":"Sub-Saharan Africa","intermediate-region":"Eastern Africa","region-code":"002","sub-region-code":"202","intermediate-region-code":"014"},{"name":"Zimbabwe","alpha-2":"ZW","alpha-3":"ZWE","country-code":"716","iso_3166-2":"ISO 3166-2:ZW","region":"Africa","sub-region":"Sub-Saharan Africa","intermediate-region":"Eastern Africa","region-code":"002","sub-region-code":"202","intermediate-region-code":"014"}]
	if filter_lobby and libretro_dict and uuid_match and discord_match:
		current_query['ip']=libretro_dict.get('ip')
		current_query['port']=libretro_dict.get('port')
		current_query['mitm_ip']=libretro_dict.get('mitm_ip')
		current_query['mitm_port']=libretro_dict.get('mitm_port')
		dict_out = {'values': {'label':'%(title)s on %(system)s'%{'title':libretro_dict.get('game_name'),'system':discord_match.get('system')},'label2':discord_match.get('game_id')},
				'info':   {'title':'%(title)s on %(system)s'%{'title':libretro_dict.get('game_name'),'system':discord_match.get('system')},
						   'originaltitle':libretro_dict.get('game_name'),
						   'date':get_date(libretro_dict.get('updated'),format_in='%Y-%m-%dT%H:%M:%SZ'),
						   'credits':re_game_tags.sub('',libretro_dict.get('username')).strip(),
						   'genre':split_value(discord_match.get('genre')),
						   'lastplayed':discord_match.get('timestamp'),
						   'plot':discord_match.get('description')+'[CR][CR]'+loc_str(30606)%{'username':re_game_tags.sub('',libretro_dict.get('username')).strip(),'country':next(iter([x.get('name') for x in country_codes if x and x.get('alpha-2').lower() == libretro_dict.get('country')]),'Unknown'),'game_name':libretro_dict.get('game_name'),'pp':libretro_dict.get('has_password'),'spectate':next(iter([not x for x in [libretro_dict.get('has_spectate_password')] if isinstance(x,bool)]),False),'core_name':libretro_dict.get('core_name'),'core_version':libretro_dict.get('core_version'),'frontend':libretro_dict.get('frontend')}},
			    'art':{'icon':'special://home/addons/plugin.program.iagl/resources/skins/Default/media/netplay_logo.png',
					  'thumb':choose_image(discord_match.get('image'),'special://home/addons/plugin.program.iagl/resources/skins/Default/media/netplay_box.jpg'),
					  'poster':choose_image(discord_match.get('image'),'special://home/addons/plugin.program.iagl/resources/skins/Default/media/netplay_box.jpg'),
					  'banner':'special://home/addons/plugin.program.iagl/resources/skins/Default/media/netplay_banner.jpg',
					  'fanart':'special://home/addons/plugin.program.iagl/resources/skins/Default/media/fanart.jpg'},
				'properties': {'route':discord_match.get('route'),
							   'query': json.dumps(current_query)},
				}
	elif not filter_lobby and libretro_dict:
		current_query['ip']=libretro_dict.get('ip')
		current_query['port']=libretro_dict.get('port')
		current_query['mitm_ip']=libretro_dict.get('mitm_ip')
		current_query['mitm_port']=libretro_dict.get('mitm_port')
		dict_out = {'values': {'label':libretro_dict.get('game_name'),'label2':libretro_dict.get('game_name')},
				'info':   {'title':libretro_dict.get('game_name'),
						   'originaltitle':libretro_dict.get('game_name'),
						   'date':get_date(libretro_dict.get('updated'),format_in='%Y-%m-%dT%H:%M:%SZ'),
						   'credits':re_game_tags.sub('',libretro_dict.get('username')).strip(),
						   'lastplayed':libretro_dict.get('created'),
						   'plot':loc_str(30606)%{'username':re_game_tags.sub('',libretro_dict.get('username')).strip(),'country':next(iter([x.get('name') for x in country_codes if x and x.get('alpha-2').lower() == libretro_dict.get('country')]),'Unknown'),'game_name':libretro_dict.get('game_name'),'pp':libretro_dict.get('has_password'),'spectate':next(iter([not x for x in [libretro_dict.get('has_spectate_password')] if isinstance(x,bool)]),False),'core_name':libretro_dict.get('core_name'),'core_version':libretro_dict.get('core_version'),'frontend':libretro_dict.get('frontend')}},
			    'art':{'icon':'special://home/addons/plugin.program.iagl/resources/skins/Default/media/netplay_logo.png',
					  'thumb':'special://home/addons/plugin.program.iagl/resources/skins/Default/media/netplay_box.jpg',
					  'poster':'special://home/addons/plugin.program.iagl/resources/skins/Default/media/netplay_box.jpg',
					  'banner':'special://home/addons/plugin.program.iagl/resources/skins/Default/media/netplay_banner.jpg',
					  'fanart':'special://home/addons/plugin.program.iagl/resources/skins/Default/media/fanart.jpg'},
				'properties': {'route':'game_search?query=%(query)s'%{'query':url_quote_query(libretro_dict)},
							   'query': json.dumps(current_query)},
				}
				
				# /%(game_id)s'%{'game_id':libretro_dict.get('core_name')}
	return dict_out

def get_libretro_dict():
	lobby_dict = None
	with requests.Session() as s:
		libretro_result = s.get('http://lobby.libretro.com/list/')
	if libretro_result.ok:
		try:
			libretro_result = json.loads(libretro_result.text)
		except Exception as exc:
			xbmc.log(msg='IAGL:  Error with libretro lobby query.  Exception %(exc)s' % {'exc': exc}, level=xbmc.LOGERROR)
	else:
		xbmc.log(msg='IAGL:  Libretro lobby returned no results. Response:  %(value)s' % {'exc': libretro_result.text}, level=xbmc.LOGERROR)
	return libretro_result

def get_discord_dict():
	discord_dict = None
	with requests.Session() as s:
		discord_result = s.get('https://discordapp.com/api/channels/%(channel)s/messages?limit=100'%{'channel':'696566635166826526'},headers={'Authorization':get_t_string('Obg Awx2BGZjZQxkZQHmZmHjBGLm.KbjSRj.bwRpgZk0f0Tg4Ucy6Z_qqvn9xFN'),'content-type':'application/json'})
	if discord_result.ok:
		try:
			discord_dict = json.loads(discord_result.text)
		except Exception as exc:
			xbmc.log(msg='IAGL:  Error with discord channel query.  Exception %(exc)s' % {'exc': exc}, level=xbmc.LOGERROR)
	else:
		xbmc.log(msg='IAGL:  Discord returned no results. Response:  %(value)s' % {'exc': discord_result.text}, level=xbmc.LOGERROR)
	return discord_dict

def get_t_string(string_in):
	if isinstance(string_in,str):
		return string_in.translate(bytes.maketrans(b'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ',b'nopqrstuvwxyzabcdefghijklmNOPQRSTUVWXYZABCDEFGHIJKLM'))
	else:
		return None

def get_crc32_from_string(string_in):
	if isinstance(string_in,str):
		return format(zlib.crc32(string_in) & 0xFFFFFFFF,'X')
	else:
		return None

def get_crc32(filename):
	crc_out = zlib_csum(filename, zlib.crc32) #First try zlib using posixpath (fast)
	if crc_out:
		return crc_out
	else:
		return zlib_csum_xbmcvfs(str(filename), zlib.crc32) #If it fails try xbmcvfs (slower)


def write_text_to_file(text_in,filename_in):
	success = False
	if filename_in and Path(filename_in):
		try:
			Path(filename_in).write_text(text_in,encoding=TEXT_ENCODING)
			success = True
		except Exception as exc:
			xbmc.log(msg='IAGL:  Error writing text file %(value_in)s.  Exception %(exc)s' % {'value_in': file_in, 'exc': exc}, level=xbmc.LOGERROR)
	elif filename_in and check_if_file_exists(filename_in):
		try:
			with xbmcvfs.File(str(filename_in), 'w') as fo:
			    fo.write(bytearray(text_in.encode('utf-8')))
			    success = True
		except:
			xbmc.log(msg='IAGL:  Error writing text file %(value_in)s.  Exception %(exc)s' % {'value_in': file_in, 'exc': exc}, level=xbmc.LOGERROR)

	else:
		success = False
	return success
# def zlib_csum(filename, func):
# 	csum = None
# 	last_read = False
# 	if filename.exists():
# 		with filename.open(mode='rb') as f:
# 			while not last_read:
# 				chunk = f.read(CHUNK_SIZE)
# 				if chunk:
# 					if csum is None:
# 						csum = func(chunk)
# 					else:
# 						csum = func(chunk, csum)
# 				else:
# 					last_read=True
# 					break
# 	if csum:
# 		return format(csum & 0xFFFFFFFF,'X')
# 	else:
# 		return None

def zlib_csum(filename, func):
	csum = None
	if filename.exists():
		with filename.open(mode='rb') as f:
			for chunk in iter((lambda:f.read(CHUNK_SIZE)),None):
				if chunk:
					if csum:
						csum = func(chunk, csum)
					else:
						csum = func(chunk)
				else:
					break
	if csum:
		return format(csum & 0xFFFFFFFF,'X')
	else:
		return None

def zlib_csum_xbmcvfs(filename, func):
	csum = None
	last_read = False
	if check_if_file_exists(filename):
		with xbmcvfs.File(str(filename)) as f:
			while not last_read:
				chunk = f.readBytes(CHUNK_SIZE)
				if chunk:
					if csum is None:
						csum = func(chunk)
					else:
						csum = func(chunk, csum)
				else:
					last_read=True
					break
	if csum:
		return format(csum & 0xFFFFFFFF,'X')
	else:
		return None

def etree_to_dict(t):
	d = {t.tag: {} if t.attrib else None}
	children = list(t)
	if children:
		dd = defaultdict(list)
		for dc in map(etree_to_dict, children):
			for k, v in dc.items():
				dd[k].append(v)
		d = {t.tag: {k: v[0] if len(v) == 1 else v for k, v in dd.items()}}
	if t.attrib:
		d[t.tag].update(('@' + k, v) for k, v in t.attrib.items())
	if t.text:
		text = t.text.strip()
		if children or t.attrib:
			if text:
				d[t.tag]['#text'] = text
		else:
			d[t.tag] = text
	return d

# def dict_to_etree(d):
# 	def _to_etree(d, root):
# 		if not d:
# 			pass
# 		elif isinstance(d, str):
# 			root.text = d
# 		elif isinstance(d, dict):
# 			for k,v in d.items():
# 				assert isinstance(k, str)
# 				if k.startswith('#'):
# 					assert k == '#text' and isinstance(v, str)
# 					root.text = v
# 				elif k.startswith('@'):
# 					assert isinstance(v, str)
# 					root.set(k[1:], v)
# 				elif isinstance(v, list):
# 					for e in v:
# 						_to_etree(e, ET.SubElement(root, k))
# 				else:
# 					_to_etree(v, ET.SubElement(root, k))
# 		else:
# 			assert d == 'invalid type', (type(d), d)
# 	assert isinstance(d, dict) and len(d) == 1
# 	tag, body = next(iter(d.items()))
# 	node = ET.Element(tag)
# 	_to_etree(body, node)
#     return node