forked from 0x2620/pandora
some info view updates
This commit is contained in:
parent
6b225333cd
commit
68f0d1117c
3 changed files with 85 additions and 55 deletions
|
@ -1,10 +1,13 @@
|
||||||
{
|
{
|
||||||
"capabilities": {
|
"capabilities": {
|
||||||
"canPlayClips": {"guest": 1, "member": 2, "staff": 3, "admin": 4},
|
"canDeleteItems": {"admin": true},
|
||||||
"canPlayVideo": {"guest": 0, "member": 1, "staff": 3, "admin": 4},
|
"canEditItemIcons": {"staff": true, "admin": true},
|
||||||
"canSeeItem": {"guest": 2, "member": 2, "staff": 3, "admin": 4},
|
"canPlayClips": {"guest": 1, "member": 2, "friend": 3, "staff": 4, "admin": 4},
|
||||||
"canSeeFiles": {"guest": -1, "member": -1, "staff": 3, "admin": 4},
|
"canPlayVideo": {"guest": 0, "member": 1, "friend": 3, "staff": 4, "admin": 4},
|
||||||
"canSeeExtraItemViews": {"guest": false, "member": false, "staff": true, "admin": true}
|
"canReloadMetadata": {"staff": true, "admin": true},
|
||||||
|
"canSeeFiles": {"guest": -1, "member": -1, "friend": -1, "staff": 4, "admin": 4},
|
||||||
|
"canSeeItem": {"guest": 2, "member": 2, "friend": 3, "staff": 4, "admin": 4},
|
||||||
|
"canSeeExtraItemViews": {"friend": true, "staff": true, "admin": true}
|
||||||
},
|
},
|
||||||
"clipKeys": [
|
"clipKeys": [
|
||||||
{"id": "clip:text", "title": "Text", "type": "string"},
|
{"id": "clip:text", "title": "Text", "type": "string"},
|
||||||
|
@ -551,7 +554,6 @@
|
||||||
"columnWidth": {}
|
"columnWidth": {}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"editIcon": false,
|
|
||||||
"find": {"conditions": [], "operator": "&"},
|
"find": {"conditions": [], "operator": "&"},
|
||||||
"groups": [
|
"groups": [
|
||||||
{"id": "director", "sort": [{"key": "items", "operator": "-"}]},
|
{"id": "director", "sort": [{"key": "items", "operator": "-"}]},
|
||||||
|
@ -580,6 +582,7 @@
|
||||||
"showFlags": true,
|
"showFlags": true,
|
||||||
"showGroups": true,
|
"showGroups": true,
|
||||||
"showHome": true,
|
"showHome": true,
|
||||||
|
"showIconBrowser": false,
|
||||||
"showInfo": true,
|
"showInfo": true,
|
||||||
"showMapControls": false,
|
"showMapControls": false,
|
||||||
"showMapLabels": false,
|
"showMapLabels": false,
|
||||||
|
@ -608,7 +611,7 @@
|
||||||
{"name": "Movies A-Z", "path": "", "items": 1234}
|
{"name": "Movies A-Z", "path": "", "items": 1234}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"userLevels": ["guest", "member", "staff", "admin"],
|
"userLevels": ["guest", "member", "friend", "staff", "admin"],
|
||||||
"video": {
|
"video": {
|
||||||
"download": false,
|
"download": false,
|
||||||
"formats": ["webm", "mp4"],
|
"formats": ["webm", "mp4"],
|
||||||
|
|
|
@ -3,46 +3,54 @@ pandora.ui.infoView = function(data) {
|
||||||
// fixme: given that currently, the info view doesn't scroll into view nicely
|
// fixme: given that currently, the info view doesn't scroll into view nicely
|
||||||
// when collapsing the movies browser, the info view should become a split panel
|
// when collapsing the movies browser, the info view should become a split panel
|
||||||
|
|
||||||
var css = {
|
var ui = pandora.user.ui,
|
||||||
|
canEditIcons = pandora.site.capabilities.canEditItemIcons[pandora.user.level],
|
||||||
|
borderRadius = ui.icons == 'posters' ? 0 : iconSize / 8,
|
||||||
|
css = {
|
||||||
marginTop: '4px',
|
marginTop: '4px',
|
||||||
textAlign: 'justify',
|
textAlign: 'justify',
|
||||||
MozUserSelect: 'text',
|
MozUserSelect: 'text',
|
||||||
WebkitUserSelect: 'text'
|
WebkitUserSelect: 'text'
|
||||||
},
|
},
|
||||||
listWidth = 144 + Ox.UI.SCROLLBAR_SIZE,
|
iconRatio = ui.icons == 'posters'
|
||||||
margin = 16,
|
? (ui.showSitePoster ? 5/8 : data.posterRatio) : 1,
|
||||||
iconSize = pandora.user.ui.infoIconSize,
|
iconSize = ui.infoIconSize,
|
||||||
iconRatio = pandora.user.ui.icons == 'posters'
|
|
||||||
? (pandora.user.ui.showSitePoster ? 5/8 : data.posterRatio) : 1,
|
|
||||||
iconWidth = iconRatio > 1 ? iconSize : Math.round(iconSize * iconRatio),
|
iconWidth = iconRatio > 1 ? iconSize : Math.round(iconSize * iconRatio),
|
||||||
iconHeight = iconRatio < 1 ? iconSize : Math.round(iconSize / iconRatio),
|
iconHeight = iconRatio < 1 ? iconSize : Math.round(iconSize / iconRatio),
|
||||||
iconLeft = iconSize == 256 ? Math.floor((iconSize - iconWidth) / 2) : 0,
|
iconLeft = iconSize == 256 ? Math.floor((iconSize - iconWidth) / 2) : 0,
|
||||||
borderRadius = pandora.user.ui.icons == 'posters' ? 0 : iconSize / 8,
|
listWidth = 144 + Ox.UI.SCROLLBAR_SIZE,
|
||||||
that = Ox.Element(),
|
margin = 16,
|
||||||
|
statisticsWidth = 128,
|
||||||
uid = Ox.uid(),
|
uid = Ox.uid(),
|
||||||
|
|
||||||
|
that = Ox.Element(),
|
||||||
|
|
||||||
$list,
|
$list,
|
||||||
|
|
||||||
$info = $('<div>')
|
$info = $('<div>')
|
||||||
.css({
|
.css({
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
left: pandora.user.level == 'admin' && !pandora.user.ui.editPoster ? -listWidth + 'px' : 0,
|
left: canEditIcons && !ui.showIconBrowser ? -listWidth + 'px' : 0,
|
||||||
top: 0,
|
top: 0,
|
||||||
right: 0,
|
right: 0,
|
||||||
})
|
})
|
||||||
.appendTo(that.$element),
|
.appendTo(that.$element),
|
||||||
|
|
||||||
$data = Ox.Container()
|
$data = Ox.Container()
|
||||||
.css({
|
.css({
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
left: (pandora.user.level == 'admin' ? listWidth : 0) + 'px',
|
left: (canEditIcons ? listWidth : 0) + 'px',
|
||||||
top: 0,
|
top: 0,
|
||||||
right: 0,
|
right: 0,
|
||||||
height: pandora.$ui.contentPanel.size(1) + 'px'
|
height: pandora.$ui.contentPanel.size(1) + 'px'
|
||||||
})
|
})
|
||||||
.appendTo($info),
|
.appendTo($info),
|
||||||
|
|
||||||
$icon = Ox.Element('<img>')
|
$icon = Ox.Element('<img>')
|
||||||
.attr({
|
.attr({
|
||||||
src: '/' + data.id + '/' + (
|
src: '/' + data.id + '/' + (
|
||||||
pandora.user.ui.icons == 'posters'
|
ui.icons == 'posters'
|
||||||
? (pandora.user.ui.showSitePoster ? 'siteposter' : 'poster') : 'icon'
|
? (ui.showSitePoster ? 'siteposter' : 'poster') : 'icon'
|
||||||
) + '512.jpg?' + uid
|
) + '512.jpg?' + uid
|
||||||
})
|
})
|
||||||
.css({
|
.css({
|
||||||
|
@ -58,6 +66,7 @@ pandora.ui.infoView = function(data) {
|
||||||
singleclick: toggleIconSize
|
singleclick: toggleIconSize
|
||||||
})
|
})
|
||||||
.appendTo($data.$element),
|
.appendTo($data.$element),
|
||||||
|
|
||||||
$reflection = $('<div>')
|
$reflection = $('<div>')
|
||||||
.addClass('OxReflection')
|
.addClass('OxReflection')
|
||||||
.css({
|
.css({
|
||||||
|
@ -69,10 +78,11 @@ pandora.ui.infoView = function(data) {
|
||||||
overflow: 'hidden'
|
overflow: 'hidden'
|
||||||
})
|
})
|
||||||
.appendTo($data.$element),
|
.appendTo($data.$element),
|
||||||
|
|
||||||
$reflectionIcon = $('<img>')
|
$reflectionIcon = $('<img>')
|
||||||
.attr({
|
.attr({
|
||||||
src: '/' + data.id + '/' + (
|
src: '/' + data.id + '/' + (
|
||||||
pandora.user.ui.icons == 'posters' ? 'poster' : 'icon'
|
ui.icons == 'posters' ? 'poster' : 'icon'
|
||||||
) + '512.jpg?' + uid
|
) + '512.jpg?' + uid
|
||||||
})
|
})
|
||||||
.css({
|
.css({
|
||||||
|
@ -83,6 +93,7 @@ pandora.ui.infoView = function(data) {
|
||||||
borderRadius: borderRadius + 'px'
|
borderRadius: borderRadius + 'px'
|
||||||
})
|
})
|
||||||
.appendTo($reflection),
|
.appendTo($reflection),
|
||||||
|
|
||||||
$reflectionGradient = $('<div>')
|
$reflectionGradient = $('<div>')
|
||||||
.css({
|
.css({
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
|
@ -90,12 +101,13 @@ pandora.ui.infoView = function(data) {
|
||||||
height: iconSize / 2 + 'px'
|
height: iconSize / 2 + 'px'
|
||||||
})
|
})
|
||||||
.appendTo($reflection),
|
.appendTo($reflection),
|
||||||
|
|
||||||
$text = $('<div>')
|
$text = $('<div>')
|
||||||
.css({
|
.css({
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
left: margin + (iconSize == 256 ? 256 : iconWidth) + margin + 'px',
|
left: margin + (iconSize == 256 ? 256 : iconWidth) + margin + 'px',
|
||||||
top: margin + 'px',
|
top: margin + 'px',
|
||||||
right: margin + 'px'
|
right: margin + statisticsWidth + margin + 'px'
|
||||||
})
|
})
|
||||||
.bind({
|
.bind({
|
||||||
click: function(e) {
|
click: function(e) {
|
||||||
|
@ -107,6 +119,16 @@ pandora.ui.infoView = function(data) {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.appendTo($data.$element),
|
.appendTo($data.$element),
|
||||||
|
|
||||||
|
$statistics = $('<div>')
|
||||||
|
.css({
|
||||||
|
position: 'absolute',
|
||||||
|
width: statisticsWidth + 'px',
|
||||||
|
top: margin + 'px',
|
||||||
|
right: margin + 'px'
|
||||||
|
})
|
||||||
|
.appendTo($data.$element),
|
||||||
|
|
||||||
$browserImages = [];
|
$browserImages = [];
|
||||||
|
|
||||||
var match = /(\(S\d{2}(E\d{2})?\))/.exec(data.title);
|
var match = /(\(S\d{2}(E\d{2})?\))/.exec(data.title);
|
||||||
|
@ -329,29 +351,31 @@ pandora.ui.infoView = function(data) {
|
||||||
|
|
||||||
$('<div>').css({height: '8px'}).appendTo($text);
|
$('<div>').css({height: '8px'}).appendTo($text);
|
||||||
|
|
||||||
if (pandora.user.level == 'admin') {
|
['hue', 'saturation', 'lightness'].forEach(function(key) {
|
||||||
|
$('<div>')
|
||||||
$icon.bindEvent({
|
.css({marginBottom: '4px'})
|
||||||
doubleclick: function() {
|
.append(formatKey(key, true))
|
||||||
pandora.UI.set('editPoster', !pandora.user.ui.editPoster);
|
.append(Ox.formatColor(data[key], key))
|
||||||
if (pandora.user.ui.editPoster) {
|
.appendTo($statistics);
|
||||||
$info.animate({
|
|
||||||
left: 0
|
|
||||||
}, 250);
|
|
||||||
} else {
|
|
||||||
$info.animate({
|
|
||||||
left: -listWidth + 'px'
|
|
||||||
}, 250);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
renderList();
|
|
||||||
|
|
||||||
|
if (canEditIcons) {
|
||||||
|
$icon.bindEvent({
|
||||||
|
doubleclick: function() {
|
||||||
|
pandora.UI.set('showIconBrowser', !ui.showIconBrowser);
|
||||||
|
$info.animate({
|
||||||
|
left: ui.showIconBrowser ? 0 : -listWidth + 'px'
|
||||||
|
}, 250);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
renderList();
|
||||||
}
|
}
|
||||||
|
|
||||||
function formatKey(key) {
|
function formatKey(key, isStatistics) {
|
||||||
return '<span style="font-weight: bold">' + Ox.toTitleCase(key) + ':</span> ';
|
return isStatistics
|
||||||
|
? $('<div>').css({marginBottom: '2px', fontWeight: 'bold'}).html(Ox.toTitleCase(key))
|
||||||
|
: '<span style="font-weight: bold">' + Ox.toTitleCase(key) + ':</span> ';
|
||||||
}
|
}
|
||||||
|
|
||||||
function formatLight(str) {
|
function formatLight(str) {
|
||||||
|
@ -369,15 +393,15 @@ pandora.ui.infoView = function(data) {
|
||||||
function renderList() {
|
function renderList() {
|
||||||
pandora.api.get({
|
pandora.api.get({
|
||||||
id: data.id,
|
id: data.id,
|
||||||
keys: [pandora.user.ui.icons == 'posters' ? 'posters' : 'frames']
|
keys: [ui.icons == 'posters' ? 'posters' : 'frames']
|
||||||
}, 0, function(result) {
|
}, 0, function(result) {
|
||||||
var images = result.data[pandora.user.ui.icons == 'posters' ? 'posters' : 'frames'],
|
var images = result.data[ui.icons == 'posters' ? 'posters' : 'frames'],
|
||||||
selectedImage = images.filter(function(image) {
|
selectedImage = images.filter(function(image) {
|
||||||
return image.selected;
|
return image.selected;
|
||||||
})[0];
|
})[0];
|
||||||
$list = Ox.IconList({
|
$list = Ox.IconList({
|
||||||
defaultRatio: pandora.user.ui.icons == 'posters' ? 5/8 : data.stream.aspectRatio,
|
defaultRatio: ui.icons == 'posters' ? 5/8 : data.stream.aspectRatio,
|
||||||
fixedRatio: pandora.user.ui.icons == 'posters' ? false : data.stream.aspectRatio,
|
fixedRatio: ui.icons == 'posters' ? false : data.stream.aspectRatio,
|
||||||
item: function(data, sort, size) {
|
item: function(data, sort, size) {
|
||||||
var ratio = data.width / data.height;
|
var ratio = data.width / data.height;
|
||||||
size = size || 128;
|
size = size || 128;
|
||||||
|
@ -385,13 +409,13 @@ pandora.ui.infoView = function(data) {
|
||||||
height: ratio <= 1 ? size : size / ratio,
|
height: ratio <= 1 ? size : size / ratio,
|
||||||
id: data['id'],
|
id: data['id'],
|
||||||
info: data.width + ' x ' + data.height + ' px',
|
info: data.width + ' x ' + data.height + ' px',
|
||||||
title: pandora.user.ui.icons == 'posters' ? data.source : Ox.formatDuration(data.position),
|
title: ui.icons == 'posters' ? data.source : Ox.formatDuration(data.position),
|
||||||
url: data.url,
|
url: data.url,
|
||||||
width: ratio >= 1 ? size : size * ratio
|
width: ratio >= 1 ? size : size * ratio
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
items: images,
|
items: images,
|
||||||
keys: pandora.user.ui.icons == 'posters'
|
keys: ui.icons == 'posters'
|
||||||
? ['index', 'source', 'width', 'height', 'url']
|
? ['index', 'source', 'width', 'height', 'url']
|
||||||
: ['index', 'position', 'width', 'height', 'url'],
|
: ['index', 'position', 'width', 'height', 'url'],
|
||||||
max: 1,
|
max: 1,
|
||||||
|
@ -421,12 +445,12 @@ pandora.ui.infoView = function(data) {
|
||||||
if ($browserImages.length == 0) {
|
if ($browserImages.length == 0) {
|
||||||
$browserImages = pandora.$ui.browser.find('img[src*="/' + data.id + '/"]');
|
$browserImages = pandora.$ui.browser.find('img[src*="/' + data.id + '/"]');
|
||||||
}
|
}
|
||||||
if (pandora.user.ui.icons == 'posters' && !pandora.user.ui.showSitePoster) {
|
if (ui.icons == 'posters' && !ui.showSitePoster) {
|
||||||
$browserImages.each(function() {
|
$browserImages.each(function() {
|
||||||
var $this = $(this),
|
var $this = $(this),
|
||||||
size = Math.max($this.width(), $this.height());
|
size = Math.max($this.width(), $this.height());
|
||||||
$this.attr({src: src});
|
$this.attr({src: src});
|
||||||
pandora.user.ui.icons == 'posters' && $this.css(imageRatio < 1 ? {
|
ui.icons == 'posters' && $this.css(imageRatio < 1 ? {
|
||||||
width: Math.round(size * imageRatio) + 'px',
|
width: Math.round(size * imageRatio) + 'px',
|
||||||
height: size + 'px'
|
height: size + 'px'
|
||||||
} : {
|
} : {
|
||||||
|
@ -440,9 +464,9 @@ pandora.ui.infoView = function(data) {
|
||||||
iconSize = iconSize == 256 ? 512 : 256;
|
iconSize = iconSize == 256 ? 512 : 256;
|
||||||
toggleIconSize();
|
toggleIconSize();
|
||||||
}
|
}
|
||||||
pandora.api[pandora.user.ui.icons == 'posters' ? 'setPoster' : 'setPosterFrame'](Ox.extend({
|
pandora.api[ui.icons == 'posters' ? 'setPoster' : 'setPosterFrame'](Ox.extend({
|
||||||
id: data.id
|
id: data.id
|
||||||
}, pandora.user.ui.icons == 'posters' ? {
|
}, ui.icons == 'posters' ? {
|
||||||
source: selectedImage.source
|
source: selectedImage.source
|
||||||
} : {
|
} : {
|
||||||
// fixme: api slightly inconsistent, this shouldn't be "position"
|
// fixme: api slightly inconsistent, this shouldn't be "position"
|
||||||
|
@ -450,14 +474,14 @@ pandora.ui.infoView = function(data) {
|
||||||
}), function() {
|
}), function() {
|
||||||
// fixme: update the info (video preview) frame as well
|
// fixme: update the info (video preview) frame as well
|
||||||
var src;
|
var src;
|
||||||
if (pandora.user.ui.icons == 'frames') {
|
if (ui.icons == 'frames') {
|
||||||
src = '/' + data.id + '/icon512.jpg?' + Ox.uid()
|
src = '/' + data.id + '/icon512.jpg?' + Ox.uid()
|
||||||
$icon.attr({src: src});
|
$icon.attr({src: src});
|
||||||
$reflectionIcon.attr({src: src});
|
$reflectionIcon.attr({src: src});
|
||||||
}
|
}
|
||||||
$browserImages.each(function() {
|
$browserImages.each(function() {
|
||||||
$(this).attr({src: '/' + data.id + '/' + (
|
$(this).attr({src: '/' + data.id + '/' + (
|
||||||
pandora.user.ui.icons == 'posters' ? 'poster' : 'icon'
|
ui.icons == 'posters' ? 'poster' : 'icon'
|
||||||
) + '64.jpg?' + Ox.uid()});
|
) + '64.jpg?' + Ox.uid()});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -473,7 +497,7 @@ pandora.ui.infoView = function(data) {
|
||||||
iconWidth = iconRatio > 1 ? iconSize : Math.round(iconSize * iconRatio);
|
iconWidth = iconRatio > 1 ? iconSize : Math.round(iconSize * iconRatio);
|
||||||
iconHeight = iconRatio < 1 ? iconSize : Math.round(iconSize / iconRatio);
|
iconHeight = iconRatio < 1 ? iconSize : Math.round(iconSize / iconRatio);
|
||||||
iconLeft = iconSize == 256 ? Math.floor((iconSize - iconWidth) / 2) : 0,
|
iconLeft = iconSize == 256 ? Math.floor((iconSize - iconWidth) / 2) : 0,
|
||||||
borderRadius = pandora.user.ui.icons == 'posters' ? 0 : iconSize / 8;
|
borderRadius = ui.icons == 'posters' ? 0 : iconSize / 8;
|
||||||
$icon.animate({
|
$icon.animate({
|
||||||
left: margin + iconLeft + 'px',
|
left: margin + iconLeft + 'px',
|
||||||
width: iconWidth + 'px',
|
width: iconWidth + 'px',
|
||||||
|
@ -503,14 +527,14 @@ pandora.ui.infoView = function(data) {
|
||||||
|
|
||||||
that.reload = function() {
|
that.reload = function() {
|
||||||
var src = src = '/' + data.id + '/' + (
|
var src = src = '/' + data.id + '/' + (
|
||||||
pandora.user.ui.icons == 'posters'
|
ui.icons == 'posters'
|
||||||
? (pandora.user.ui.showSitePoster ? 'siteposter' : 'poster') : 'icon'
|
? (ui.showSitePoster ? 'siteposter' : 'poster') : 'icon'
|
||||||
) + '512.jpg?' + Ox.uid()
|
) + '512.jpg?' + Ox.uid()
|
||||||
$icon.attr({src: src});
|
$icon.attr({src: src});
|
||||||
$reflectionIcon.attr({src: src});
|
$reflectionIcon.attr({src: src});
|
||||||
iconSize = iconSize == 256 ? 512 : 256;
|
iconSize = iconSize == 256 ? 512 : 256;
|
||||||
iconRatio = pandora.user.ui.icons == 'posters'
|
iconRatio = ui.icons == 'posters'
|
||||||
? (pandora.user.ui.showSitePoster ? 5/8 : data.posterRatio) : 1;
|
? (ui.showSitePoster ? 5/8 : data.posterRatio) : 1;
|
||||||
toggleIconSize();
|
toggleIconSize();
|
||||||
pandora.user.level == 'admin' && $list.replaceWith($list = renderList());
|
pandora.user.level == 'admin' && $list.replaceWith($list = renderList());
|
||||||
};
|
};
|
||||||
|
@ -524,7 +548,7 @@ pandora.ui.infoView = function(data) {
|
||||||
that.bindEvent({
|
that.bindEvent({
|
||||||
pandora_icons: that.reload,
|
pandora_icons: that.reload,
|
||||||
pandora_showsiteposter: function() {
|
pandora_showsiteposter: function() {
|
||||||
pandora.user.ui.icons == 'posters' && that.reload();
|
ui.icons == 'posters' && that.reload();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,10 @@ pandora.ui.toolbar = function() {
|
||||||
pandora.$ui.orderButton = pandora.ui.orderButton()
|
pandora.$ui.orderButton = pandora.ui.orderButton()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (ui.item && ui.itemView == 'info' && pandora.user.level == 'admin') {
|
if (
|
||||||
|
ui.item && ui.itemView == 'info'
|
||||||
|
&& pandora.site.capabilities.canReloadMetadata[pandora.user.level]
|
||||||
|
) {
|
||||||
that.append(
|
that.append(
|
||||||
Ox.Button({
|
Ox.Button({
|
||||||
title: 'Reload Metadata'
|
title: 'Reload Metadata'
|
||||||
|
|
Loading…
Reference in a new issue