2015-03-17 17:51:45 +00:00
|
|
|
#################################################################################################
|
|
|
|
# ReadEmbyDB
|
|
|
|
#################################################################################################
|
|
|
|
|
|
|
|
import xbmc
|
|
|
|
import xbmcgui
|
|
|
|
import xbmcaddon
|
|
|
|
import json
|
|
|
|
|
|
|
|
from DownloadUtils import DownloadUtils
|
|
|
|
|
2015-03-25 17:37:21 +00:00
|
|
|
addon = xbmcaddon.Addon(id='plugin.video.emby')
|
2015-03-17 17:51:45 +00:00
|
|
|
|
|
|
|
class ReadEmbyDB():
|
2015-04-03 02:12:09 +00:00
|
|
|
def getMovies(self, id, fullinfo = False, fullSync = True, itemList = []):
|
2015-03-17 17:51:45 +00:00
|
|
|
result = None
|
|
|
|
|
2015-03-25 17:37:21 +00:00
|
|
|
addon = xbmcaddon.Addon(id='plugin.video.emby')
|
2015-03-17 17:51:45 +00:00
|
|
|
port = addon.getSetting('port')
|
|
|
|
host = addon.getSetting('ipaddress')
|
|
|
|
server = host + ":" + port
|
|
|
|
|
|
|
|
downloadUtils = DownloadUtils()
|
2015-03-18 15:47:55 +00:00
|
|
|
userid = downloadUtils.getUserId()
|
|
|
|
|
2015-04-03 02:12:09 +00:00
|
|
|
if fullSync:
|
2015-03-18 15:47:55 +00:00
|
|
|
sortstring = "&SortBy=SortName"
|
2015-04-03 02:12:09 +00:00
|
|
|
else:
|
|
|
|
if(len(itemList) > 0): # if we want a certain list specify it
|
2015-04-03 08:38:51 +00:00
|
|
|
#sortstring = "&Ids=" + ",".join(itemList)
|
|
|
|
sortstring = "" # work around for now until ParetnId and Id work together
|
2015-04-03 02:12:09 +00:00
|
|
|
else: # just get the last 20 created items
|
|
|
|
sortstring = "&Limit=20&SortBy=DateCreated"
|
|
|
|
|
2015-03-17 17:51:45 +00:00
|
|
|
if fullinfo:
|
2015-03-18 15:47:55 +00:00
|
|
|
url = server + '/mediabrowser/Users/' + userid + '/items?ParentId=' + id + sortstring + '&Fields=Path,Genres,SortName,Studios,Writer,ProductionYear,Taglines,CommunityRating,OfficialRating,CumulativeRunTimeTicks,Metascore,AirTime,DateCreated,MediaStreams,People,Overview&Recursive=true&SortOrder=Descending&IncludeItemTypes=Movie&CollapseBoxSetItems=false&format=json&ImageTypeLimit=1'
|
2015-03-17 17:51:45 +00:00
|
|
|
else:
|
2015-03-18 15:47:55 +00:00
|
|
|
url = server + '/mediabrowser/Users/' + userid + '/items?ParentId=' + id + sortstring + '&Fields=CumulativeRunTimeTicks&Recursive=true&SortOrder=Descending&IncludeItemTypes=Movie&CollapseBoxSetItems=false&format=json&ImageTypeLimit=1'
|
2015-04-03 02:12:09 +00:00
|
|
|
|
2015-03-25 12:48:29 +00:00
|
|
|
jsonData = downloadUtils.downloadUrl(url, suppress=False, popup=0)
|
2015-03-17 17:51:45 +00:00
|
|
|
if jsonData != None and jsonData != "":
|
|
|
|
result = json.loads(jsonData)
|
|
|
|
if(result.has_key('Items')):
|
|
|
|
result = result['Items']
|
|
|
|
|
2015-04-03 08:38:51 +00:00
|
|
|
# work around for now until ParetnId and Id work together
|
|
|
|
if(result != None and len(result) > 0 and len(itemList) > 0):
|
|
|
|
newResult = []
|
|
|
|
for item in result:
|
|
|
|
if(item.get("Id") in itemList):
|
|
|
|
newResult.append(item)
|
|
|
|
result = newResult
|
|
|
|
|
2015-03-17 17:51:45 +00:00
|
|
|
return result
|
2015-03-21 13:31:30 +00:00
|
|
|
|
|
|
|
def getMusicVideos(self, fullinfo = False, fullSync = True):
|
|
|
|
result = None
|
|
|
|
|
2015-03-25 17:37:21 +00:00
|
|
|
addon = xbmcaddon.Addon(id='plugin.video.emby')
|
2015-03-21 13:31:30 +00:00
|
|
|
port = addon.getSetting('port')
|
|
|
|
host = addon.getSetting('ipaddress')
|
|
|
|
server = host + ":" + port
|
|
|
|
|
|
|
|
downloadUtils = DownloadUtils()
|
|
|
|
userid = downloadUtils.getUserId()
|
|
|
|
|
|
|
|
if not fullSync:
|
|
|
|
sortstring = "&Limit=20&SortBy=DateCreated"
|
|
|
|
else:
|
|
|
|
sortstring = "&SortBy=SortName"
|
|
|
|
|
|
|
|
if fullinfo:
|
|
|
|
url = server + '/mediabrowser/Users/' + userid + '/items?' + sortstring + '&Fields=Path,Genres,SortName,Studios,Writer,ProductionYear,Taglines,CommunityRating,OfficialRating,CumulativeRunTimeTicks,Metascore,AirTime,DateCreated,MediaStreams,People,Overview&Recursive=true&SortOrder=Descending&IncludeItemTypes=MusicVideo&format=json&ImageTypeLimit=1'
|
|
|
|
else:
|
|
|
|
url = server + '/mediabrowser/Users/' + userid + '/items?' + sortstring + '&Fields=CumulativeRunTimeTicks&Recursive=true&SortOrder=Descending&IncludeItemTypes=MusicVideo&CollapseBoxSetItems=false&format=json&ImageTypeLimit=1'
|
|
|
|
|
2015-03-25 12:48:29 +00:00
|
|
|
jsonData = downloadUtils.downloadUrl(url, suppress=False, popup=0)
|
2015-03-21 13:31:30 +00:00
|
|
|
if jsonData != None and jsonData != "":
|
|
|
|
result = json.loads(jsonData)
|
|
|
|
if(result.has_key('Items')):
|
|
|
|
result = result['Items']
|
|
|
|
|
|
|
|
return result
|
|
|
|
|
2015-03-19 17:40:29 +00:00
|
|
|
def getItem(self, id):
|
|
|
|
result = None
|
|
|
|
|
2015-03-25 17:37:21 +00:00
|
|
|
addon = xbmcaddon.Addon(id='plugin.video.emby')
|
2015-03-19 17:40:29 +00:00
|
|
|
port = addon.getSetting('port')
|
|
|
|
host = addon.getSetting('ipaddress')
|
|
|
|
server = host + ":" + port
|
|
|
|
|
|
|
|
downloadUtils = DownloadUtils()
|
|
|
|
userid = downloadUtils.getUserId()
|
|
|
|
|
|
|
|
jsonData = downloadUtils.downloadUrl("http://" + server + "/mediabrowser/Users/" + userid + "/Items/" + id + "?format=json&ImageTypeLimit=1", suppress=False, popup=1 )
|
|
|
|
if jsonData != None and jsonData != "":
|
|
|
|
result = json.loads(jsonData)
|
|
|
|
|
|
|
|
return result
|
|
|
|
|
2015-03-25 14:00:08 +00:00
|
|
|
def getFullItem(self, id):
|
|
|
|
result = None
|
|
|
|
|
2015-03-25 17:37:21 +00:00
|
|
|
addon = xbmcaddon.Addon(id='plugin.video.emby')
|
2015-03-25 14:00:08 +00:00
|
|
|
port = addon.getSetting('port')
|
|
|
|
host = addon.getSetting('ipaddress')
|
|
|
|
server = host + ":" + port
|
|
|
|
|
|
|
|
downloadUtils = DownloadUtils()
|
|
|
|
userid = downloadUtils.getUserId()
|
|
|
|
|
|
|
|
jsonData = downloadUtils.downloadUrl("http://" + server + "/mediabrowser/Users/" + userid + "/Items/" + id + "?format=json", suppress=False, popup=1 )
|
|
|
|
if jsonData != None and jsonData != "":
|
|
|
|
result = json.loads(jsonData)
|
|
|
|
|
|
|
|
return result
|
|
|
|
|
2015-03-18 17:00:38 +00:00
|
|
|
def getTVShows(self, fullinfo = False, fullSync = False):
|
2015-03-17 17:51:45 +00:00
|
|
|
result = None
|
|
|
|
|
2015-03-25 17:37:21 +00:00
|
|
|
addon = xbmcaddon.Addon(id='plugin.video.emby')
|
2015-03-17 17:51:45 +00:00
|
|
|
port = addon.getSetting('port')
|
|
|
|
host = addon.getSetting('ipaddress')
|
|
|
|
server = host + ":" + port
|
|
|
|
|
|
|
|
downloadUtils = DownloadUtils()
|
2015-03-18 17:00:38 +00:00
|
|
|
userid = downloadUtils.getUserId()
|
|
|
|
|
|
|
|
if not fullSync:
|
|
|
|
sortstring = "&Limit=20&SortBy=DateCreated"
|
|
|
|
else:
|
|
|
|
sortstring = "&SortBy=SortName"
|
|
|
|
|
2015-03-17 17:51:45 +00:00
|
|
|
|
|
|
|
if fullinfo:
|
2015-03-18 17:00:38 +00:00
|
|
|
url = server + '/mediabrowser/Users/' + userid + '/Items?' + sortstring + '&Fields=Path,Genres,SortName,Studios,Writer,ProductionYear,Taglines,CommunityRating,OfficialRating,CumulativeRunTimeTicks,Metascore,AirTime,DateCreated,MediaStreams,People,Overview&Recursive=true&SortOrder=Descending&IncludeItemTypes=Series&format=json&ImageTypeLimit=1'
|
2015-03-17 17:51:45 +00:00
|
|
|
else:
|
2015-03-18 17:00:38 +00:00
|
|
|
url = server + '/mediabrowser/Users/' + userid + '/Items?' + sortstring + '&Fields=CumulativeRunTimeTicks&Recursive=true&SortOrder=Descending&IncludeItemTypes=Series&format=json&ImageTypeLimit=1'
|
2015-03-17 17:51:45 +00:00
|
|
|
|
2015-03-25 12:48:29 +00:00
|
|
|
jsonData = downloadUtils.downloadUrl(url, suppress=False, popup=0)
|
2015-03-19 21:31:06 +00:00
|
|
|
if jsonData != None and jsonData != "":
|
|
|
|
result = json.loads(jsonData)
|
|
|
|
if(result.has_key('Items')):
|
|
|
|
result = result['Items']
|
|
|
|
|
|
|
|
return result
|
|
|
|
|
|
|
|
def getTVShowSeasons(self, tvShowId):
|
|
|
|
result = None
|
|
|
|
|
2015-03-25 17:37:21 +00:00
|
|
|
addon = xbmcaddon.Addon(id='plugin.video.emby')
|
2015-03-19 21:31:06 +00:00
|
|
|
port = addon.getSetting('port')
|
|
|
|
host = addon.getSetting('ipaddress')
|
|
|
|
server = host + ":" + port
|
|
|
|
|
|
|
|
downloadUtils = DownloadUtils()
|
|
|
|
userid = downloadUtils.getUserId()
|
|
|
|
|
|
|
|
url = 'http://' + server + '/Shows/' + tvShowId + '/Seasons?UserId=' + userid + '&format=json&ImageTypeLimit=1'
|
|
|
|
|
2015-03-25 12:48:29 +00:00
|
|
|
jsonData = downloadUtils.downloadUrl(url, suppress=False, popup=0)
|
2015-03-17 17:51:45 +00:00
|
|
|
if jsonData != None and jsonData != "":
|
|
|
|
result = json.loads(jsonData)
|
|
|
|
if(result.has_key('Items')):
|
|
|
|
result = result['Items']
|
|
|
|
|
|
|
|
return result
|
2015-03-18 17:00:38 +00:00
|
|
|
|
2015-03-17 17:51:45 +00:00
|
|
|
def getEpisodes(self, showId, fullinfo = False):
|
|
|
|
result = None
|
|
|
|
|
2015-03-25 17:37:21 +00:00
|
|
|
addon = xbmcaddon.Addon(id='plugin.video.emby')
|
2015-03-17 17:51:45 +00:00
|
|
|
port = addon.getSetting('port')
|
|
|
|
host = addon.getSetting('ipaddress')
|
|
|
|
server = host + ":" + port
|
|
|
|
|
|
|
|
downloadUtils = DownloadUtils()
|
|
|
|
userid = downloadUtils.getUserId()
|
|
|
|
|
|
|
|
if fullinfo:
|
|
|
|
url = server + '/mediabrowser/Users/' + userid + '/Items?ParentId=' + showId + '&IsVirtualUnaired=false&IsMissing=False&SortBy=SortName&Fields=Path,Genres,SortName,Studios,Writer,ProductionYear,Taglines,CommunityRating,OfficialRating,CumulativeRunTimeTicks,Metascore,AirTime,DateCreated,MediaStreams,People,Overview&Recursive=true&SortOrder=Ascending&IncludeItemTypes=Episode&format=json&ImageTypeLimit=1'
|
|
|
|
else:
|
|
|
|
url = server + '/mediabrowser/Users/' + userid + '/Items?ParentId=' + showId + '&IsVirtualUnaired=false&IsMissing=False&SortBy=SortName&Fields=Name,SortName,CumulativeRunTimeTicks&Recursive=true&SortOrder=Ascending&IncludeItemTypes=Episode&format=json&ImageTypeLimit=1'
|
|
|
|
|
2015-03-25 12:48:29 +00:00
|
|
|
jsonData = downloadUtils.downloadUrl(url, suppress=False, popup=0)
|
2015-03-17 17:51:45 +00:00
|
|
|
|
|
|
|
if jsonData != None and jsonData != "":
|
|
|
|
result = json.loads(jsonData)
|
|
|
|
if(result.has_key('Items')):
|
|
|
|
result = result['Items']
|
|
|
|
return result
|
|
|
|
|
2015-04-03 02:12:09 +00:00
|
|
|
def getLatestEpisodes(self, fullinfo = False, itemList = []):
|
2015-03-18 17:00:38 +00:00
|
|
|
result = None
|
|
|
|
|
2015-03-25 17:37:21 +00:00
|
|
|
addon = xbmcaddon.Addon(id='plugin.video.emby')
|
2015-03-18 17:00:38 +00:00
|
|
|
port = addon.getSetting('port')
|
|
|
|
host = addon.getSetting('ipaddress')
|
|
|
|
server = host + ":" + port
|
|
|
|
|
|
|
|
downloadUtils = DownloadUtils()
|
|
|
|
userid = downloadUtils.getUserId()
|
|
|
|
|
2015-04-03 02:12:09 +00:00
|
|
|
limitString = "Limit=20&SortBy=DateCreated&"
|
|
|
|
if(len(itemList) > 0): # if we want a certain list specify it
|
|
|
|
limitString = "Ids=" + ",".join(itemList) + "&"
|
|
|
|
|
2015-03-18 17:00:38 +00:00
|
|
|
if fullinfo:
|
2015-04-03 02:12:09 +00:00
|
|
|
url = server + '/mediabrowser/Users/' + userid + '/Items?' + limitString + 'IsVirtualUnaired=false&IsMissing=False&Fields=ParentId,Path,Genres,SortName,Studios,Writer,ProductionYear,Taglines,CommunityRating,OfficialRating,CumulativeRunTimeTicks,Metascore,AirTime,DateCreated,MediaStreams,People,Overview&Recursive=true&SortOrder=Descending&IncludeItemTypes=Episode&format=json&ImageTypeLimit=1'
|
2015-03-18 17:00:38 +00:00
|
|
|
else:
|
2015-04-03 02:12:09 +00:00
|
|
|
url = server + '/mediabrowser/Users/' + userid + '/Items?' + limitString + 'IsVirtualUnaired=false&IsMissing=False&Fields=ParentId,Name,SortName,CumulativeRunTimeTicks&Recursive=true&SortOrder=Descending&IncludeItemTypes=Episode&format=json&ImageTypeLimit=1'
|
2015-03-18 17:00:38 +00:00
|
|
|
|
2015-03-25 12:48:29 +00:00
|
|
|
jsonData = downloadUtils.downloadUrl(url, suppress=False, popup=0)
|
2015-03-18 17:00:38 +00:00
|
|
|
|
|
|
|
if jsonData != None and jsonData != "":
|
|
|
|
result = json.loads(jsonData)
|
|
|
|
if(result.has_key('Items')):
|
|
|
|
result = result['Items']
|
|
|
|
return result
|
|
|
|
|
2015-03-17 17:51:45 +00:00
|
|
|
def getCollections(self, type):
|
|
|
|
#Build a list of the user views
|
2015-03-22 21:22:03 +00:00
|
|
|
userid = DownloadUtils().getUserId()
|
2015-03-25 17:37:21 +00:00
|
|
|
addon = xbmcaddon.Addon(id='plugin.video.emby')
|
2015-03-22 21:22:03 +00:00
|
|
|
port = addon.getSetting('port')
|
|
|
|
host = addon.getSetting('ipaddress')
|
|
|
|
server = host + ":" + port
|
|
|
|
downloadUtils = DownloadUtils()
|
|
|
|
|
|
|
|
try:
|
|
|
|
jsonData = downloadUtils.downloadUrl("http://" + server + "/mediabrowser/Users/" + userid + "/Items/Root?format=json")
|
|
|
|
except Exception, msg:
|
|
|
|
error = "Get connect : " + str(msg)
|
|
|
|
xbmc.log (error)
|
|
|
|
return []
|
|
|
|
|
|
|
|
if(jsonData == ""):
|
|
|
|
return []
|
|
|
|
|
|
|
|
result = json.loads(jsonData)
|
|
|
|
|
|
|
|
parentid = result.get("Id")
|
|
|
|
|
|
|
|
htmlpath = ("http://%s/mediabrowser/Users/" % server)
|
|
|
|
jsonData = downloadUtils.downloadUrl(htmlpath + userid + "/items?ParentId=" + parentid + "&Sortby=SortName&format=json")
|
|
|
|
collections=[]
|
|
|
|
|
|
|
|
if(jsonData == ""):
|
|
|
|
return []
|
|
|
|
|
|
|
|
result = json.loads(jsonData)
|
|
|
|
result = result.get("Items")
|
|
|
|
|
|
|
|
for item in result:
|
|
|
|
if(item.get("RecursiveItemCount") != 0):
|
|
|
|
Temp = item.get("Name")
|
|
|
|
Name = Temp.encode('utf-8')
|
|
|
|
section = item.get("CollectionType")
|
|
|
|
type = item.get("CollectionType")
|
|
|
|
if type == None:
|
|
|
|
type = "None" # User may not have declared the type
|
2015-03-22 21:48:17 +00:00
|
|
|
if type == type and item.get("Name") != "Collections":
|
2015-03-22 21:22:03 +00:00
|
|
|
collections.append( {'title' : item.get("Name"),
|
|
|
|
'type' : type,
|
|
|
|
'id' : item.get("Id")})
|
|
|
|
return collections
|
|
|
|
|
|
|
|
def getViewCollections(self, type):
|
|
|
|
#Build a list of the user views
|
2015-03-17 17:51:45 +00:00
|
|
|
userid = DownloadUtils().getUserId()
|
2015-03-25 17:37:21 +00:00
|
|
|
addon = xbmcaddon.Addon(id='plugin.video.emby')
|
2015-03-17 17:51:45 +00:00
|
|
|
port = addon.getSetting('port')
|
|
|
|
host = addon.getSetting('ipaddress')
|
|
|
|
server = host + ":" + port
|
|
|
|
|
|
|
|
viewsUrl = server + "/mediabrowser/Users/" + userid + "/Views?format=json&ImageTypeLimit=1"
|
2015-03-25 12:48:29 +00:00
|
|
|
jsonData = DownloadUtils().downloadUrl(viewsUrl, suppress=False, popup=0 )
|
2015-03-18 02:45:15 +00:00
|
|
|
collections=[]
|
2015-03-17 17:51:45 +00:00
|
|
|
|
|
|
|
if(jsonData != ""):
|
|
|
|
views = json.loads(jsonData)
|
|
|
|
views = views.get("Items")
|
2015-03-18 02:45:15 +00:00
|
|
|
|
2015-03-17 17:51:45 +00:00
|
|
|
for view in views:
|
|
|
|
if view.get("Type") == 'UserView': # Need to grab the real main node
|
|
|
|
newViewsUrl = server + '/mediabrowser/Users/' + userid + '/items?ParentId=' + view.get("Id") + '&SortBy=SortName&SortOrder=Ascending&format=json&ImageTypeLimit=1'
|
2015-03-25 12:48:29 +00:00
|
|
|
jsonData = DownloadUtils().downloadUrl(newViewsUrl, suppress=False, popup=0 )
|
2015-03-17 17:51:45 +00:00
|
|
|
if(jsonData != ""):
|
|
|
|
newViews = json.loads(jsonData)
|
|
|
|
newViews = newViews.get("Items")
|
|
|
|
for newView in newViews:
|
|
|
|
# There are multiple nodes in here like 'Latest', 'NextUp' - below we grab the full node.
|
|
|
|
if newView.get("CollectionType") == "MovieMovies" or newView.get("CollectionType") == "TvShowSeries":
|
|
|
|
view=newView
|
|
|
|
if(view.get("ChildCount") != 0):
|
2015-03-17 20:18:27 +00:00
|
|
|
Name =(view.get("Name"))
|
2015-03-17 17:51:45 +00:00
|
|
|
|
|
|
|
total = str(view.get("ChildCount"))
|
|
|
|
type = view.get("CollectionType")
|
|
|
|
if type == None:
|
|
|
|
type = "None" # User may not have declared the type
|
|
|
|
if type == type:
|
|
|
|
collections.append( {'title' : Name,
|
|
|
|
'type' : type,
|
|
|
|
'id' : view.get("Id")})
|
|
|
|
return collections
|
2015-03-24 16:47:26 +00:00
|
|
|
|
|
|
|
def getBoxSets(self):
|
|
|
|
result = None
|
|
|
|
|
2015-03-25 17:37:21 +00:00
|
|
|
addon = xbmcaddon.Addon(id='plugin.video.emby')
|
2015-03-24 16:47:26 +00:00
|
|
|
port = addon.getSetting('port')
|
|
|
|
host = addon.getSetting('ipaddress')
|
|
|
|
server = host + ":" + port
|
|
|
|
|
|
|
|
downloadUtils = DownloadUtils()
|
|
|
|
userid = downloadUtils.getUserId()
|
|
|
|
|
|
|
|
url = server + '/mediabrowser/Users/' + userid + '/Items?SortBy=SortName&IsVirtualUnaired=false&IsMissing=False&Fields=Name,SortName,CumulativeRunTimeTicks&Recursive=true&SortOrder=Ascending&IncludeItemTypes=BoxSet&format=json&ImageTypeLimit=1'
|
|
|
|
|
2015-03-25 12:48:29 +00:00
|
|
|
jsonData = downloadUtils.downloadUrl(url, suppress=False, popup=0)
|
2015-03-24 16:47:26 +00:00
|
|
|
|
|
|
|
if jsonData != None and jsonData != "":
|
|
|
|
result = json.loads(jsonData)
|
|
|
|
if(result.has_key('Items')):
|
|
|
|
result = result['Items']
|
|
|
|
return result
|
|
|
|
|
|
|
|
def getMoviesInBoxSet(self,boxsetId):
|
|
|
|
result = None
|
|
|
|
|
2015-03-25 17:37:21 +00:00
|
|
|
addon = xbmcaddon.Addon(id='plugin.video.emby')
|
2015-03-24 16:47:26 +00:00
|
|
|
port = addon.getSetting('port')
|
|
|
|
host = addon.getSetting('ipaddress')
|
|
|
|
server = host + ":" + port
|
|
|
|
|
|
|
|
downloadUtils = DownloadUtils()
|
|
|
|
userid = downloadUtils.getUserId()
|
|
|
|
|
|
|
|
url = server + '/mediabrowser/Users/' + userid + '/Items?ParentId=' + boxsetId + '&Fields=ItemCounts&format=json&ImageTypeLimit=1'
|
|
|
|
|
2015-03-25 12:48:29 +00:00
|
|
|
jsonData = downloadUtils.downloadUrl(url, suppress=False, popup=0)
|
2015-03-24 16:47:26 +00:00
|
|
|
|
|
|
|
if jsonData != None and jsonData != "":
|
|
|
|
result = json.loads(jsonData)
|
|
|
|
if(result.has_key('Items')):
|
|
|
|
result = result['Items']
|
|
|
|
return result
|
2015-03-17 17:51:45 +00:00
|
|
|
|