Resolve Oracle status
This commit is contained in:
parent
98ff399ee6
commit
676e90bb5e
87
app/my.js
87
app/my.js
|
@ -33,5 +33,88 @@ function randomString(len) {
|
|||
return pwd;
|
||||
}
|
||||
|
||||
exports.randomString=randomString;
|
||||
exports.Recursion=Recursion;
|
||||
function compArray(array1,array2){
|
||||
if((array1&&typeof array1 ==="object"&&array1.constructor===Array)&&(array2&&typeof array2 ==="object"&&array2.constructor===Array)){
|
||||
if(array1.length==array2.length){
|
||||
for(var i=0;i<array1.length;i++){
|
||||
var ggg=compObj(array1[i],array2[i]);
|
||||
if(!ggg)
|
||||
return false;
|
||||
}
|
||||
|
||||
}else{
|
||||
return false;
|
||||
}
|
||||
}else{
|
||||
throw new Error("argunment is error ;");
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
function compObj(obj1,obj2){//比较两个对象是否相等,不包含原形上的属性计较
|
||||
if((obj1&&typeof obj1==="object")&&((obj2&&typeof obj2==="object"))){
|
||||
var count1=propertyLength(obj1);
|
||||
var count2=propertyLength(obj2);
|
||||
if(count1==count2){
|
||||
for(var ob in obj1){
|
||||
if(obj1.hasOwnProperty(ob)&&obj2.hasOwnProperty(ob)){
|
||||
if(obj1[ob].constructor==Array&&obj2[ob].constructor==Array){//如果属性是数组
|
||||
if(!compArray(obj1[ob],obj2[ob])){
|
||||
return false;
|
||||
};
|
||||
}else if(typeof obj1[ob]==="string"&&typeof obj2[ob]==="string"){//纯属性
|
||||
if(obj1[ob]!==obj2[ob]){
|
||||
return false;
|
||||
}
|
||||
}else if(typeof obj1[ob]==="object"&&typeof obj2[ob]==="object"){//属性是对象
|
||||
if(!compObj(obj1[ob],obj2[ob])){
|
||||
return false;
|
||||
};
|
||||
}else{
|
||||
return false;
|
||||
}
|
||||
}else{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
function propertyLength(obj){//获得对象上的属性个数,不包含对象原形上的属性
|
||||
var count=0;
|
||||
if(obj&&typeof obj==="object") {
|
||||
for(var ooo in obj) {
|
||||
if(obj.hasOwnProperty(ooo)) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}else {
|
||||
throw new Error("argunment can not be null;");
|
||||
}
|
||||
};
|
||||
|
||||
function selectorMatches(selector,labels){
|
||||
if(typeof(selector) === 'object'){
|
||||
var answer = true;
|
||||
var count = 0;
|
||||
for(var key in selector){
|
||||
count++;
|
||||
if(answer && labels[key] !== selector[key])
|
||||
answer = false;
|
||||
}
|
||||
|
||||
return answer && count > 0;
|
||||
}else{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
exports.randomString = randomString;
|
||||
exports.Recursion = Recursion;
|
||||
exports.compObj = compObj;
|
||||
exports.selectorMatches = selectorMatches;
|
|
@ -205,4 +205,5 @@ declare module Kubernetes {
|
|||
function createRC(obj: any, onCompleteFn?: any): void;
|
||||
function updateReplicationControllerLabels($http: any, KubernetesApiURL: any, replicationController: any, newLabels: any, onCompleteFn?: any): void;
|
||||
function connectOracle($http: any, $timeout: any, url: any, connectParam: any, rcName: any, delayTime: any): void;
|
||||
function getOracleStatus(labels: any): number;
|
||||
}
|
||||
|
|
|
@ -1,71 +0,0 @@
|
|||
/// <reference path="d.ts/includes.d.ts"/>
|
||||
/// <reference path="d.ts/kubernetes/ts/kubernetesInterfaces.d.ts"/>
|
||||
/// <reference path="d.ts/kubernetes/ts/kubernetesHelpers.d.ts"/>
|
||||
/// <reference path="d.ts/developer/ts/developerEnrichers.d.ts"/>
|
||||
/// <reference path="d.ts/developer/ts/developerHelpers.d.ts"/>
|
||||
/// <reference path="d.ts/developer/ts/developerNavigation.d.ts"/>
|
||||
/// <reference path="d.ts/developer/ts/FileMode.d.ts"/>
|
||||
/// <reference path="d.ts/developer/ts/developerPlugin.d.ts"/>
|
||||
/// <reference path="d.ts/developer/ts/environmentPanel.d.ts"/>
|
||||
/// <reference path="d.ts/developer/ts/home.d.ts"/>
|
||||
/// <reference path="d.ts/developer/ts/jenkinsJob.d.ts"/>
|
||||
/// <reference path="d.ts/developer/ts/jenkinsJobs.d.ts"/>
|
||||
/// <reference path="d.ts/kubernetes/ts/kubernetesPlugin.d.ts"/>
|
||||
/// <reference path="d.ts/kubernetes/ts/kubernetesModel.d.ts"/>
|
||||
/// <reference path="d.ts/developer/ts/jenkinsLog.d.ts"/>
|
||||
/// <reference path="d.ts/developer/ts/jenkinsMetrics.d.ts"/>
|
||||
/// <reference path="d.ts/developer/ts/navbar.d.ts"/>
|
||||
/// <reference path="d.ts/developer/ts/pipeline.d.ts"/>
|
||||
/// <reference path="d.ts/developer/ts/pipelineDirective.d.ts"/>
|
||||
/// <reference path="d.ts/developer/ts/pipelines.d.ts"/>
|
||||
/// <reference path="d.ts/developer/ts/project.d.ts"/>
|
||||
/// <reference path="d.ts/developer/ts/projectSelector.d.ts"/>
|
||||
/// <reference path="d.ts/developer/ts/projects.d.ts"/>
|
||||
/// <reference path="d.ts/developer/ts/workspace.d.ts"/>
|
||||
/// <reference path="d.ts/developer/ts/workspaces.d.ts"/>
|
||||
/// <reference path="d.ts/kubernetes/ts/apps.d.ts"/>
|
||||
/// <reference path="d.ts/kubernetes/ts/breadcrumbs.d.ts"/>
|
||||
/// <reference path="d.ts/kubernetes/ts/build.d.ts"/>
|
||||
/// <reference path="d.ts/kubernetes/ts/buildConfig.d.ts"/>
|
||||
/// <reference path="d.ts/kubernetes/ts/buildConfigEdit.d.ts"/>
|
||||
/// <reference path="d.ts/kubernetes/ts/buildConfigs.d.ts"/>
|
||||
/// <reference path="d.ts/kubernetes/ts/buildLogs.d.ts"/>
|
||||
/// <reference path="d.ts/kubernetes/ts/builds.d.ts"/>
|
||||
/// <reference path="d.ts/kubernetes/ts/connect.d.ts"/>
|
||||
/// <reference path="d.ts/kubernetes/ts/dataInfnModel.d.ts"/>
|
||||
/// <reference path="d.ts/kubernetes/ts/deploymentConfig.d.ts"/>
|
||||
/// <reference path="d.ts/kubernetes/ts/deploymentConfigs.d.ts"/>
|
||||
/// <reference path="d.ts/kubernetes/ts/events.d.ts"/>
|
||||
/// <reference path="d.ts/kubernetes/ts/host.d.ts"/>
|
||||
/// <reference path="d.ts/kubernetes/ts/utilHelpers.d.ts"/>
|
||||
/// <reference path="d.ts/kubernetes/ts/hosts.d.ts"/>
|
||||
/// <reference path="d.ts/kubernetes/ts/imageRepositories.d.ts"/>
|
||||
/// <reference path="d.ts/kubernetes/ts/kubernetesNavigation.d.ts"/>
|
||||
/// <reference path="d.ts/kubernetes/ts/schema.d.ts"/>
|
||||
/// <reference path="d.ts/kubernetes/ts/kubernetesSchema.d.ts"/>
|
||||
/// <reference path="d.ts/kubernetes/ts/kubernetesServices.d.ts"/>
|
||||
/// <reference path="d.ts/kubernetes/ts/kubernetesTopLevel.d.ts"/>
|
||||
/// <reference path="d.ts/kubernetes/ts/namespace.d.ts"/>
|
||||
/// <reference path="d.ts/kubernetes/ts/oracleStatusModel.d.ts"/>
|
||||
/// <reference path="d.ts/kubernetes/ts/overview.d.ts"/>
|
||||
/// <reference path="d.ts/kubernetes/ts/pipelines.d.ts"/>
|
||||
/// <reference path="d.ts/kubernetes/ts/pod.d.ts"/>
|
||||
/// <reference path="d.ts/kubernetes/ts/podEdit.d.ts"/>
|
||||
/// <reference path="d.ts/kubernetes/ts/watcher.d.ts"/>
|
||||
/// <reference path="d.ts/kubernetes/ts/term.d.ts"/>
|
||||
/// <reference path="d.ts/kubernetes/ts/podLogs.d.ts"/>
|
||||
/// <reference path="d.ts/kubernetes/ts/pods.d.ts"/>
|
||||
/// <reference path="d.ts/kubernetes/ts/replicationController.d.ts"/>
|
||||
/// <reference path="d.ts/kubernetes/ts/replicationControllerEdit.d.ts"/>
|
||||
/// <reference path="d.ts/kubernetes/ts/replicationControllers.d.ts"/>
|
||||
/// <reference path="d.ts/kubernetes/ts/schemaHelpers.d.ts"/>
|
||||
/// <reference path="d.ts/kubernetes/ts/secret.d.ts"/>
|
||||
/// <reference path="d.ts/kubernetes/ts/secrets.d.ts"/>
|
||||
/// <reference path="d.ts/kubernetes/ts/service.d.ts"/>
|
||||
/// <reference path="d.ts/kubernetes/ts/serviceEdit.d.ts"/>
|
||||
/// <reference path="d.ts/kubernetes/ts/serviceRegistry.d.ts"/>
|
||||
/// <reference path="d.ts/kubernetes/ts/services.d.ts"/>
|
||||
/// <reference path="d.ts/kubernetes/ts/sharedControllers.d.ts"/>
|
||||
/// <reference path="d.ts/kubernetes/ts/tabs.d.ts"/>
|
||||
/// <reference path="d.ts/kubernetes/ts/templates.d.ts"/>
|
||||
/// <reference path="d.ts/navigation/ts/navigationPlugin.d.ts"/>
|
File diff suppressed because one or more lines are too long
129
gulpfile.js
129
gulpfile.js
|
@ -19,7 +19,7 @@ var gulp = require('gulp'),
|
|||
shellprocess = require('child_process'),
|
||||
xmloperation = require('./app/xmloperation'),
|
||||
rootdir = process.env.STORAGE_PATH || '/home/server_data/',
|
||||
k8s = require('k8s'),
|
||||
K8s = require('k8s'),
|
||||
crontab = require('node-crontab'),
|
||||
myjs=require('./app/my.js');
|
||||
|
||||
|
@ -29,9 +29,10 @@ var plugins = gulpLoadPlugins({});
|
|||
var pkg = require('./package.json');
|
||||
var time =0;
|
||||
var schedule = [];
|
||||
var kubectl = k8s.kubectl({
|
||||
endpoint: process.env.KUBERNETES_MASTER
|
||||
, binary: '/usr/bin/kubectl'
|
||||
|
||||
var kubectl = K8s.kubectl({
|
||||
endpoint: 'http://192.168.0.102:8080',
|
||||
binary: '/usr/bin/kubectl'
|
||||
});
|
||||
|
||||
var config = {
|
||||
|
@ -546,20 +547,11 @@ gulp.task('connect', ['watch'], function() {
|
|||
|
||||
hawtio.use('/connectToOracle',function(req,res){
|
||||
var rcName = req.query.oracleName;
|
||||
var connectParam = req.query.param;
|
||||
var taskIndex = -1;
|
||||
for(var index in schedule){
|
||||
var connectionTask = schedule[index];
|
||||
if(connectionTask.hasOwnProperty("taskName") && connectionTask.taskName === rcName){
|
||||
clearInterval(connectionTask[taskCrontab]);
|
||||
taskIndex = index;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(taskIndex !== -1)
|
||||
schedule.splice(taskIndex,1);
|
||||
|
||||
cancelOracleConectionTask(rcName);
|
||||
|
||||
kubectl.rc.get(rcName,function(err, rc){
|
||||
console.log(rc);
|
||||
//console.log(rc);
|
||||
if(err){
|
||||
console.log(err);
|
||||
return
|
||||
|
@ -570,40 +562,60 @@ gulp.task('connect', ['watch'], function() {
|
|||
taskName: rcName,
|
||||
taskTime: 0,
|
||||
taskCrontab: crontab.scheduleJob("*/1 * * * *", function(){ //This will call this function every 2 minutes
|
||||
console.log(rcName + "it's been 1 minutes!");
|
||||
//console.log(rcName + "it's been 1 minutes!");
|
||||
if(task.taskTime === 9){
|
||||
kubectl.command("label rc " +rcName + " status=2 --overwrite" ,function(err, data){
|
||||
kubectl.rc.command("label --overwrite rc " + task.taskName + " status=1", function(err, data){
|
||||
if(err)
|
||||
console.log(err);
|
||||
crontab.cancelJob(task.taskCrontab);
|
||||
cancelOracleConectionTask(task.rcName);
|
||||
});
|
||||
}
|
||||
/*kubectl.
|
||||
oracledb.getConnection(
|
||||
{
|
||||
user : "system",
|
||||
password : "oracle",
|
||||
connectString : connectParam+"/orcl"
|
||||
},function(err, connection){
|
||||
if (err) {
|
||||
console.log("connection failed! message" + err.message);
|
||||
return;
|
||||
}
|
||||
console.log("connect success!");
|
||||
kubectl.command("label rc " +rcName + " status=1 --overwrite" ,function(err, data){
|
||||
if(err)
|
||||
console.log(err);
|
||||
crontab.cancelJob(task.taskCrontab);
|
||||
|
||||
var selectorPods = [];
|
||||
kubectl.pod.list(function(err, pods){
|
||||
if(!err){
|
||||
pods.items.forEach(function(item){
|
||||
if(myjs.selectorMatches(selector, item.metadata.labels))
|
||||
selectorPods.push(item);
|
||||
});
|
||||
if(connection !== null){
|
||||
connection.close(function(err){
|
||||
if (err){
|
||||
console.error(err.message);
|
||||
if(selectorPods.length === 0)
|
||||
return;
|
||||
var host = selectorPods[0].status.hostIP
|
||||
var port = selectorPods[0].spec.containers[0].ports[0].hostPort;
|
||||
|
||||
if(host && port){
|
||||
oracledb.getConnection(
|
||||
{
|
||||
user : "system",
|
||||
password : "oracle",
|
||||
connectString : host + ":" + port + "/orcl"
|
||||
},function(err, connection){
|
||||
if (err) {
|
||||
console.log("connection failed! message" + err.message);
|
||||
return;
|
||||
}
|
||||
console.log("connection closed!");
|
||||
console.log("connect success!");
|
||||
kubectl.rc.command("label --overwrite rc " + task.taskName + " status=2", function(err, data){
|
||||
if(err){
|
||||
console.log(err);
|
||||
}
|
||||
console.log("update replicationControllers " + rcName + " success");
|
||||
if(connection !== null){
|
||||
connection.close(function(err){
|
||||
if (err){
|
||||
console.error(err.message);
|
||||
}
|
||||
crontab.cancelJob(task.taskCrontab);
|
||||
cancelOracleConectionTask(task.rcName);
|
||||
console.log("connection closed!");
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
});*/
|
||||
}
|
||||
});
|
||||
task.taskTime++;
|
||||
})
|
||||
}
|
||||
|
@ -615,21 +627,7 @@ gulp.task('connect', ['watch'], function() {
|
|||
});
|
||||
hawtio.use('/cancelOracleConection',function(req,res){
|
||||
var rcName = req.query.oracleName;
|
||||
console.log(rcName);
|
||||
var taskIndex = -1;
|
||||
for(var index in schedule){
|
||||
var connectionTask = schedule[index];
|
||||
console.log(connectionTask.taskName);
|
||||
if(connectionTask.hasOwnProperty("taskName") && connectionTask.taskName === rcName){
|
||||
console.log(connectionTask.taskCrontab);
|
||||
clearInterval(connectionTask.taskCrontab);
|
||||
console.log("connectionTask: " + rcName + "cancel");
|
||||
taskIndex = index;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(taskIndex !== -1)
|
||||
schedule.splice(taskIndex,1);
|
||||
cancelOracleConectionTask(rcName);
|
||||
res.send(200,"Ok");
|
||||
res.end();
|
||||
});
|
||||
|
@ -668,7 +666,24 @@ gulp.task('site', ['clean', 'build'], function() {
|
|||
|
||||
gulp.task('default', ['connect']);
|
||||
|
||||
|
||||
function cancelOracleConectionTask(taskName){
|
||||
var taskIndex = -1;
|
||||
for(var index in schedule){
|
||||
var connectionTask = schedule[index];
|
||||
if(connectionTask.hasOwnProperty("taskName") && connectionTask.taskName === taskName){
|
||||
crontab.cancelJob(connectionTask.taskCrontab);
|
||||
console.log("Connection Task(taskName: " + taskName + ")" + " Canceled!");
|
||||
taskIndex = index;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(taskIndex !== -1){
|
||||
schedule.splice(taskIndex,1);
|
||||
console.log("Remove task(taskName: " + taskName + ") from schedule");
|
||||
}else{
|
||||
console.log("There Are No Connection Task(taskName: " + taskName + ")" + " Can be Canceled!");
|
||||
}
|
||||
}
|
||||
function geFileList(path)
|
||||
{
|
||||
var filesList = [];
|
||||
|
|
|
@ -25,7 +25,9 @@
|
|||
<script type="text/ng-template" id="podCountsAndLinkTemplate.html">
|
||||
<div class="ngCellText" ng-init="entity=row.entity" ng-controller="Kubernetes.Status">
|
||||
<a ng-show="row.entity.$podCounters.podsLink" title="pods status">
|
||||
<span ng-show="row.entity.$podCounters.ready" class="badge badge-success" > 启动</span>
|
||||
<span ng-show="row.entity.$podCounters.ready && (row.entity.$oracleStatus===2)" class="badge badge-success" > 启动</span>
|
||||
<span ng-show="row.entity.$podCounters.ready && (row.entity.$oracleStatus===0)" class="badge badge-info" > 等待</span>
|
||||
<span ng-show="row.entity.$podCounters.ready && (row.entity.$oracleStatus===1)" class="badge badge-warning" > 失败</span>
|
||||
<span ng-show="row.entity.$podCounters.valid || row.entity.$podCounters.waiting" class="badge badge-info"> 等待</span>
|
||||
<span ng-show="!(row.entity.$podCounters.waiting || row.entity.$podCounters.ready || row.entity.$podCounters.valid || row.entity.$podCounters.error)" class="badge"> 停止</span>
|
||||
<span ng-show="row.entity.$podCounters.error" class="badge badge-warning" > 失败</span>
|
||||
|
|
|
@ -1788,5 +1788,23 @@ module Kubernetes {
|
|||
}, delayTime);
|
||||
}
|
||||
|
||||
|
||||
export function getOracleStatus(labels){
|
||||
var answer = -1;
|
||||
if(typeof(labels) === 'object' && labels.hasOwnProperty("status")){
|
||||
switch(labels.status){
|
||||
case '0':
|
||||
answer = 0;
|
||||
break;
|
||||
case '1':
|
||||
answer = 1;
|
||||
break;
|
||||
case '2':
|
||||
answer = 2;
|
||||
break;
|
||||
default:
|
||||
answer = -1;
|
||||
}
|
||||
}
|
||||
return answer;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -340,6 +340,8 @@ module Kubernetes {
|
|||
replicationController.$podCount = replicationController.$pods.length;
|
||||
replicationController.$replicas = (replicationController.spec || {}).replicas;
|
||||
|
||||
replicationController.$oracleStatus = getOracleStatus(getLabels(replicationController));
|
||||
|
||||
var selectedPods = replicationController.$pods;
|
||||
replicationController.connectTo = selectedPods.map((pod) => {
|
||||
return pod._key;
|
||||
|
|
|
@ -86,8 +86,10 @@ module Kubernetes {
|
|||
id: getName(next)
|
||||
}, undefined, () => {
|
||||
log.debug("deleted: ", getName(next));
|
||||
if(next.metadata.labels.style === "oracle")
|
||||
if(next.metadata.labels.style === "oracle"){
|
||||
console.log("delete " + next.metadata.name);
|
||||
Kubernetes.connectOracle($http, $timeout, "/cancelOracleConection", "", getName(next), 0);
|
||||
}
|
||||
deleteSelected(selected, selected.shift());
|
||||
}, (error) => {
|
||||
log.debug("Error deleting: ", error);
|
||||
|
@ -163,8 +165,10 @@ module Kubernetes {
|
|||
function stopSelected(selected:Array<KubePod>, next:KubePod) {
|
||||
if (next) {
|
||||
Kubernetes.resizeController($http, KubernetesApiURL, next, 0, () => {
|
||||
if(next.metadata.labels.style === "oracle")
|
||||
if(next.metadata.labels.style === "oracle"){
|
||||
console.log("stop " + next.metadata.name);
|
||||
Kubernetes.connectOracle($http, $timeout, "/cancelOracleConection", "", getName(next), 0);
|
||||
}
|
||||
stopSelected(selected, selected.shift());
|
||||
});
|
||||
}
|
||||
|
@ -187,6 +191,7 @@ module Kubernetes {
|
|||
if(next){
|
||||
if(next.$replicas === 0)
|
||||
Kubernetes.resizeController($http, KubernetesApiURL, next, 1, () => {
|
||||
console.log("restart " + next.metadata.name);
|
||||
Kubernetes.connectOracle($http, $timeout, "/connectToOracle", "", getName(next), 0);
|
||||
startSelected(selected, selected.shift());
|
||||
});
|
||||
|
|
|
@ -95,33 +95,9 @@ module Kubernetes {
|
|||
|
||||
//服务状态过滤
|
||||
export var Status = controller('Status', ["$scope", "$http", "$interval", "$location", "KubernetesApiURL", ($scope, $http, $interval, $location, KubernetesApiURL) => {
|
||||
$scope.$watch('entity', (newValue, oldValue) => {
|
||||
if(newValue){
|
||||
//console.log($scope.entity.metadata.labels);
|
||||
if($scope.entity.metadata.labels.status === "0" && $scope.entity.metadata.labels.lock === "0"){
|
||||
var labels =
|
||||
Kubernetes.updateReplicationControllerLabels($http, KubernetesApiURL, $scope.entity, {"style": "oracle", "status": "0", "lock": "1"});
|
||||
var ip = $scope.entity.$pods[0].$host + ":" + $scope.entity.$pods[0].spec.containers[0].ports[0].hostPort;
|
||||
var timer = $interval(() => {
|
||||
$http({
|
||||
url:'/connectToOracle',
|
||||
method:'POST',
|
||||
params:{param: ip}
|
||||
}).success(function(data,header,config,status){
|
||||
if(header === 200){
|
||||
console.log(data);
|
||||
$interval.cancel(timer);
|
||||
}
|
||||
}).error(function(data,header,config,status){
|
||||
|
||||
});
|
||||
}, 60000, 10);
|
||||
|
||||
timer.then(() => {
|
||||
console.log("All Connect Done!");
|
||||
});
|
||||
}
|
||||
}
|
||||
},true);
|
||||
//$scope.$watch('entity', (newValue, oldValue) => {
|
||||
// if(newValue)
|
||||
// console.log(newValue);
|
||||
//},true);
|
||||
}]);
|
||||
}
|
||||
|
|
|
@ -52,7 +52,7 @@ module Kubernetes {
|
|||
public createRC(Obj){
|
||||
var labels = {
|
||||
"style": "oracle",
|
||||
"status": "created"
|
||||
"status": "0"
|
||||
};
|
||||
for(var item in Obj.labels)
|
||||
labels[item] = Obj.labels[item];
|
||||
|
|
Loading…
Reference in New Issue