mirror of
https://gitee.com/rainbond/Rainbond.git
synced 2024-12-02 03:37:46 +08:00
528 lines
28 KiB
JSON
528 lines
28 KiB
JSON
|
{
|
||
|
"swagger": "2.0",
|
||
|
"paths": {
|
||
|
"/v2/job": {
|
||
|
"get": {
|
||
|
"description": "get job list",
|
||
|
"produces": [
|
||
|
"application/json"
|
||
|
],
|
||
|
"tags": [
|
||
|
"v2"
|
||
|
],
|
||
|
"summary": "获取job列表",
|
||
|
"operationId": "JobList",
|
||
|
"parameters": [
|
||
|
{
|
||
|
"type": "string",
|
||
|
"format": "string",
|
||
|
"description": "node name",
|
||
|
"name": "node",
|
||
|
"in": "form"
|
||
|
},
|
||
|
{
|
||
|
"type": "string",
|
||
|
"format": "string",
|
||
|
"description": "group name",
|
||
|
"name": "group",
|
||
|
"in": "form"
|
||
|
}
|
||
|
],
|
||
|
"responses": {
|
||
|
"200": {
|
||
|
"description": "{\"ok\":true}"
|
||
|
}
|
||
|
}
|
||
|
},
|
||
|
"put": {
|
||
|
"description": "add or update job",
|
||
|
"produces": [
|
||
|
"application/json"
|
||
|
],
|
||
|
"tags": [
|
||
|
"v2"
|
||
|
],
|
||
|
"summary": "添加或者更新job",
|
||
|
"operationId": "UpdateJob",
|
||
|
"parameters": [
|
||
|
{
|
||
|
"type": "json",
|
||
|
"format": "string",
|
||
|
"description": "{\"id\":\"\",\"kind\":0,\"name\":\"aac\",\"oldGroup\":\"\",\"group\":\"default\",\"user\":\"\",\"cmd\":\"echo \\\"hello \\\"\u003e/tmp/aac.txt\",\"pause\":true,\"parallels\":0,\"timeout\":0,\"interval\":0,\"retry\":0,\"rules\":[{\"id\":\"NEW0.5930536330436825\",\"nids\":[\"172.16.0.118\"],\"timer\":\"* 5 * * * *\",\"exclude_nids\":[\"172.16.0.131\"]}],\"fail_notify\":false,\"to\":[]}",
|
||
|
"name": "job",
|
||
|
"in": "body",
|
||
|
"required": true
|
||
|
}
|
||
|
],
|
||
|
"responses": {
|
||
|
"200": {
|
||
|
"description": "{\"ok\":true}"
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
},
|
||
|
"/v2/job/group": {
|
||
|
"get": {
|
||
|
"description": "get all groups",
|
||
|
"produces": [
|
||
|
"application/json"
|
||
|
],
|
||
|
"tags": [
|
||
|
"v2"
|
||
|
],
|
||
|
"summary": "获取所有job的group",
|
||
|
"operationId": "GetAllGroup",
|
||
|
"responses": {
|
||
|
"200": {
|
||
|
"description": "[\"group1\",...]"
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
},
|
||
|
"/v2/job/{group}-{id}": {
|
||
|
"get": {
|
||
|
"description": "get job by group and id",
|
||
|
"produces": [
|
||
|
"application/json"
|
||
|
],
|
||
|
"tags": [
|
||
|
"v2"
|
||
|
],
|
||
|
"summary": "获取 job",
|
||
|
"operationId": "GetJob",
|
||
|
"parameters": [
|
||
|
{
|
||
|
"type": "string",
|
||
|
"format": "string",
|
||
|
"description": "group name",
|
||
|
"name": "group",
|
||
|
"in": "path",
|
||
|
"required": true
|
||
|
},
|
||
|
{
|
||
|
"type": "string",
|
||
|
"format": "string",
|
||
|
"description": "job id",
|
||
|
"name": "id",
|
||
|
"in": "path",
|
||
|
"required": true
|
||
|
}
|
||
|
],
|
||
|
"responses": {
|
||
|
"200": {
|
||
|
"description": "{\"id\":\"\",\"kind\":0,\"name\":\"aac\",\"group\":\"default\",\"user\":\"\",\"cmd\":\"echo \\\"hello \\\"\u003e/tmp/aac.txt\",\"pause\":true,\"parallels\":0,\"timeout\":0,\"interval\":0,\"retry\":0,\"rules\":[{\"id\":\"NEW0.5930536330436825\",\"nids\":[\"172.16.0.118\"],\"timer\":\"* 5 * * * *\",\"exclude_nids\":[\"172.16.0.131\"]}],\"fail_notify\":false,\"to\":[]}"
|
||
|
}
|
||
|
}
|
||
|
},
|
||
|
"post": {
|
||
|
"description": "change job status",
|
||
|
"produces": [
|
||
|
"application/json"
|
||
|
],
|
||
|
"tags": [
|
||
|
"v2"
|
||
|
],
|
||
|
"summary": "更改 job 状态",
|
||
|
"operationId": "ChangeJobStatus",
|
||
|
"parameters": [
|
||
|
{
|
||
|
"type": "string",
|
||
|
"format": "string",
|
||
|
"description": "group name",
|
||
|
"name": "group",
|
||
|
"in": "path",
|
||
|
"required": true
|
||
|
},
|
||
|
{
|
||
|
"type": "string",
|
||
|
"format": "string",
|
||
|
"description": "job id",
|
||
|
"name": "id",
|
||
|
"in": "path",
|
||
|
"required": true
|
||
|
},
|
||
|
{
|
||
|
"type": "string",
|
||
|
"format": "string",
|
||
|
"description": "{\"id\":\"\",\"kind\":0,\"name\":\"aac\",\"group\":\"default\",\"user\":\"\",\"cmd\":\"echo \\\"hello \\\"\u003e/tmp/aac.txt\",\"pause\":true,\"parallels\":0,\"timeout\":0,\"interval\":0,\"retry\":0,\"rules\":[{\"id\":\"NEW0.5930536330436825\",\"nids\":[\"172.16.0.118\"],\"timer\":\"* 5 * * * *\",\"exclude_nids\":[\"172.16.0.131\"]}],\"fail_notify\":false,\"to\":[]}",
|
||
|
"in": "body",
|
||
|
"required": true
|
||
|
}
|
||
|
],
|
||
|
"responses": {
|
||
|
"200": {
|
||
|
"description": "{\"id\":\"\",\"kind\":0,\"name\":\"aac\",\"group\":\"default\",\"user\":\"\",\"cmd\":\"echo \\\"hello \\\"\u003e/tmp/aac.txt\",\"pause\":true,\"parallels\":0,\"timeout\":0,\"interval\":0,\"retry\":0,\"rules\":[{\"id\":\"NEW0.5930536330436825\",\"nids\":[\"172.16.0.118\"],\"timer\":\"* 5 * * * *\",\"exclude_nids\":[\"172.16.0.131\"]}],\"fail_notify\":false,\"to\":[]}"
|
||
|
}
|
||
|
}
|
||
|
},
|
||
|
"delete": {
|
||
|
"description": "delete job by group and id",
|
||
|
"produces": [
|
||
|
"application/json"
|
||
|
],
|
||
|
"tags": [
|
||
|
"v2"
|
||
|
],
|
||
|
"summary": "删除 job",
|
||
|
"operationId": "DeleteJob",
|
||
|
"parameters": [
|
||
|
{
|
||
|
"type": "string",
|
||
|
"format": "string",
|
||
|
"description": "group name",
|
||
|
"name": "group",
|
||
|
"in": "path",
|
||
|
"required": true
|
||
|
},
|
||
|
{
|
||
|
"type": "string",
|
||
|
"format": "string",
|
||
|
"description": "job id",
|
||
|
"name": "id",
|
||
|
"in": "path",
|
||
|
"required": true
|
||
|
}
|
||
|
],
|
||
|
"responses": {
|
||
|
"200": {
|
||
|
"description": "{\"ok\":true}"
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
},
|
||
|
"/v2/job/{group}-{id}/execute/{name}": {
|
||
|
"put": {
|
||
|
"description": "execute job",
|
||
|
"produces": [
|
||
|
"application/json"
|
||
|
],
|
||
|
"tags": [
|
||
|
"v2"
|
||
|
],
|
||
|
"summary": "立即在 node上 执行一次指定group/id 的job",
|
||
|
"operationId": "JobExecute",
|
||
|
"parameters": [
|
||
|
{
|
||
|
"type": "string",
|
||
|
"format": "string",
|
||
|
"description": "group name",
|
||
|
"name": "group",
|
||
|
"in": "path",
|
||
|
"required": true
|
||
|
},
|
||
|
{
|
||
|
"type": "string",
|
||
|
"format": "string",
|
||
|
"description": "job id",
|
||
|
"name": "id",
|
||
|
"in": "path",
|
||
|
"required": true
|
||
|
},
|
||
|
{
|
||
|
"type": "string",
|
||
|
"format": "string",
|
||
|
"description": "node name",
|
||
|
"name": "name",
|
||
|
"in": "path",
|
||
|
"required": true
|
||
|
}
|
||
|
],
|
||
|
"responses": {
|
||
|
"200": {
|
||
|
"description": "{\"ok\":true}"
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
},
|
||
|
"/v2/job/{group}-{id}/nodes": {
|
||
|
"get": {
|
||
|
"description": "get job runnable nodes",
|
||
|
"produces": [
|
||
|
"application/json"
|
||
|
],
|
||
|
"tags": [
|
||
|
"v2"
|
||
|
],
|
||
|
"summary": "获取job的可执行节点",
|
||
|
"operationId": "GetJobNodes",
|
||
|
"parameters": [
|
||
|
{
|
||
|
"type": "string",
|
||
|
"format": "string",
|
||
|
"description": "group name",
|
||
|
"name": "group",
|
||
|
"in": "path",
|
||
|
"required": true
|
||
|
},
|
||
|
{
|
||
|
"type": "string",
|
||
|
"format": "string",
|
||
|
"description": "job id",
|
||
|
"name": "id",
|
||
|
"in": "path",
|
||
|
"required": true
|
||
|
}
|
||
|
],
|
||
|
"responses": {
|
||
|
"200": {
|
||
|
"description": "[\"10.1.1.2\",...]"
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
},
|
||
|
"/v2/node": {
|
||
|
"get": {
|
||
|
"description": "get node list info from etcd",
|
||
|
"produces": [
|
||
|
"application/json"
|
||
|
],
|
||
|
"tags": [
|
||
|
"v2"
|
||
|
],
|
||
|
"summary": "从etcd获取节点简单列表信息",
|
||
|
"operationId": "GetNodeList",
|
||
|
"responses": {
|
||
|
"200": {
|
||
|
"description": "[{\"uuid\": \"ccc\", \"Status\":\"create\",\"host_name\": \"10.0.55.73\", \"internal_ip\": \"10.0.55.73\", \"external_ip\": \"10.0.55.73\", \"available_memory\": 16267956, \"available_cpu\": 4, \"role\": \"\", \"labels\": {\"key1\": \"value1\"}, \"unschedulable\": false},{}]"
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
},
|
||
|
"/v2/node/details/{node}": {
|
||
|
"get": {
|
||
|
"description": "get node details info from k8s\n",
|
||
|
"produces": [
|
||
|
"application/json"
|
||
|
],
|
||
|
"tags": [
|
||
|
"v2"
|
||
|
],
|
||
|
"summary": "从服务器获取节点详细信息",
|
||
|
"operationId": "GetNodeDetails",
|
||
|
"parameters": [
|
||
|
{
|
||
|
"type": "string",
|
||
|
"format": "string",
|
||
|
"description": "nodeuid",
|
||
|
"name": "name",
|
||
|
"in": "path",
|
||
|
"required": true
|
||
|
}
|
||
|
],
|
||
|
"responses": {
|
||
|
"200": {
|
||
|
"description": "{\"metadata\":{\"name\":\"10.0.55.73\",\"selfLink\":\"/api/v1/nodes10.0.55.73\",\"uid\":\"84014c3d-985c-11e7-bab9-00163e020ab5\",\"resourceVersion\":\"25615083\",\"creationTimestamp\":\"2017-09-13T08:21:17Z\",\"labels\":{\"key1\":\"value1\"},\"annotations\":{\"node.alpha.kubernetes.io/ttl\":\"0\",\"volumes.kubernetes.io/controller-managed-attach-detach\":\"true\"}},\"spec\":{\"externalID\":\"10.0.55.73\"},\"status\":{\"capacity\":{\"cpu\":\"4\",\"memory\":\"16267956Ki\",\"pods\":\"10k\"},\"allocatable\":{\"cpu\":\"4\",\"memory\":\"16165556Ki\",\"pods\":\"10k\"},\"conditions\":[{\"type\":\"OutOfDisk\",\"status\":\"False\",\"lastHeartbeatTime\":\"2017-09-13T10:41:16Z\",\"lastTransitionTime\":\"2017-09-13T10:20:27Z\",\"reason\":\"KubeletHasSufficientDisk\",\"message\":\"kubelet has sufficient disk space available\"},{\"type\":\"MemoryPressure\",\"status\":\"False\",\"lastHeartbeatTime\":\"2017-09-13T10:41:16Z\",\"lastTransitionTime\":\"2017-09-13T10:20:27Z\",\"reason\":\"KubeletHasSufficientMemory\",\"message\":\"kubelet has sufficient memory available\"},{\"type\":\"DiskPressure\",\"status\":\"False\",\"lastHeartbeatTime\":\"2017-09-13T10:41:16Z\",\"lastTransitionTime\":\"2017-09-13T10:20:27Z\",\"reason\":\"KubeletHasNoDiskPressure\",\"message\":\"kubelet has no disk pressure\"},{\"type\":\"Ready\",\"status\":\"True\",\"lastHeartbeatTime\":\"2017-09-13T10:41:16Z\",\"lastTransitionTime\":\"2017-09-13T10:38:25Z\",\"reason\":\"KubeletReady\",\"message\":\"kubelet is posting ready status\"}],\"addresses\":[{\"type\":\"Hostname\",\"address\":\"10.0.55.73\"},{\"type\":\"InternalIP\",\"address\":\"10.0.55.73\"},{\"type\":\"LegacyHostIP\",\"address\":\"10.0.55.73\"}],\"daemonEndpoints\":{\"kubeletEndpoint\":{\"Port\":10250}},\"nodeInfo\":{\"machineID\":\"df39b3efbcee4d5c84b2feab34009235\",\"systemUUID\":\"08A7D00A-C4B6-4AB7-8D8D-DA14C104A4DC\",\"bootID\":\"b4cd3c6c-e18d-43ae-9f11-3125110e9179\",\"kernelVersion\":\"3.10.0-514.21.2.el7.x86_64\",\"osImage\":\"CentOS Linux 7 (Core)\",\"containerRuntimeVersion\":\"docker://1.12.6\",\"kubeletVersion\":\"v1.6.4-48+61221fc61897e2-dirty\",\"kubeProxyVersion\":\"v1.6.4-48+61221fc61897e2-dirty\",\"operatingSystem\":\"linux\",\"architecture\":\"amd64\"},\"images\":[{\"names\":[\"goodrain.me/2e4c4e027008_dockerfile_spark-2.2.0-alluxio@sha256:ce197c224ff66443a08f7dfc9fed760c32757dd0f0679799b9d269d9db51e13d\",\"goodrain.me/2e4c4e027008_dockerfile_spark-2.2.0-alluxio:20170830143118\",\"goodrain.me/2e4c4e027008_dockerfile_spark-2.2.0-alluxio:20170830184733\"],\"sizeBytes\":2647820101},{\"names\":[\"goodrain.me/2e4c4e027008_dockerfile_spark-2.2.0-alluxio@sha256:8f9eb080bbf1d3032345fb8706ae0745501a1efa1fcea8f50f5dbafce4c84b65\",\"goodrain.me/2e4c4e027008_goodrain-apps_spark-2.2.0-alluxio@sha256:8f9eb080bbf1d3032345fb8706ae0745501a1efa1fcea8f50f5dbafce4c84b65\",\"goodrain.me/88c078b8ea97_dockerfile_spark-2.2.0-alluxio@sha256:8f9eb080bbf1d3032345fb8706ae0745501a1efa1fcea8f50f5dbafce4c84b65\",\"goodrain.me/2e4c4e027008_dockerfile_spark-2.2.0-alluxio:20170830142750\",\"goodrain.me/2e4c4e027008_goodrain-apps_spark-2.2.0-alluxio:20170830122343\"],\"sizeBytes\":2647820100},{\"names\":[\"goodrain.me/2e4c4e027008_goodrain-apps_spark-2.2.0-alluxio@sha256:19249e625e7a8ab1855ce95ae4fcc9ad97577953f2699ace4c9b804da085c867\",\"goodrain.me/2e4c4e027008_goodrain-apps_spark-2.2.0-alluxio:20170830113536\",\"goodrain.me/2e4c4e027008_goodrain-apps_spark-2.2.0-alluxio:20170830115858\"],\"sizeBytes\":2647820048},{\"names\":[\"goodrain.me/2e4c4e027008_goodrain-apps_spark-2.2.0-alluxio@sha256:c6145a1fa0eb1a042498d5e00269ce8d84712b35b47ebb93e41065f63aea31da\",\"goodrain.me/2e4c4e027008_goodrain-apps_spark-2.2.0-alluxio:20170830112150\"],\"sizeBytes\":2647819994},{\"names\":[\"goodrain.me/goodrain/spark@sha256:9fd5e07fccc7fb368745b44890ccf78faf3bb81fb5989ad215383385681ef368\",\"goodrain.me/goodrain/spark:2.2.0-alluxio_gr3920e2\",\"goodrain.me/goodrain/spark:2.2.0-alluxio_gr3920e2_gr1ed98b\"],\"sizeBytes\":2647819621},{\"names\":[\"goodrain.me/runner@sha256:6e9a4e759aa087ea0fa0e376d821dde301ec1ef78
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
},
|
||
|
"/v2/node/{name}": {
|
||
|
"delete": {
|
||
|
"description": "delete node from etcd",
|
||
|
"produces": [
|
||
|
"application/json"
|
||
|
],
|
||
|
"tags": [
|
||
|
"v2"
|
||
|
],
|
||
|
"summary": "从etcd 删除计算节点",
|
||
|
"operationId": "DeleteFromDB",
|
||
|
"parameters": [
|
||
|
{
|
||
|
"type": "string",
|
||
|
"format": "string",
|
||
|
"description": "nodeuid",
|
||
|
"name": "name",
|
||
|
"in": "path",
|
||
|
"required": true
|
||
|
}
|
||
|
],
|
||
|
"responses": {
|
||
|
"200": {
|
||
|
"description": "{\"ok\":true}"
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
},
|
||
|
"/v2/node/{name}/label": {
|
||
|
"post": {
|
||
|
"description": "add label to node",
|
||
|
"produces": [
|
||
|
"application/json"
|
||
|
],
|
||
|
"tags": [
|
||
|
"v2"
|
||
|
],
|
||
|
"summary": "为node添加label",
|
||
|
"operationId": "AddLabel",
|
||
|
"parameters": [
|
||
|
{
|
||
|
"type": "string",
|
||
|
"format": "string",
|
||
|
"description": "nodeuid",
|
||
|
"name": "name",
|
||
|
"in": "path",
|
||
|
"required": true
|
||
|
},
|
||
|
{
|
||
|
"type": "string",
|
||
|
"format": "string",
|
||
|
"description": "{\"LKey\":\"key1\",\"LValue\":\"value1\"}",
|
||
|
"in": "body",
|
||
|
"required": true
|
||
|
}
|
||
|
],
|
||
|
"responses": {
|
||
|
"200": {
|
||
|
"description": "{\"ok\":true}"
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
},
|
||
|
"/v2/node/{name}/reschedulable": {
|
||
|
"put": {
|
||
|
"description": "make node schedulable",
|
||
|
"produces": [
|
||
|
"application/json"
|
||
|
],
|
||
|
"tags": [
|
||
|
"v2"
|
||
|
],
|
||
|
"summary": "使节点可调度",
|
||
|
"operationId": "UnCordon",
|
||
|
"parameters": [
|
||
|
{
|
||
|
"type": "string",
|
||
|
"format": "string",
|
||
|
"description": "nodeuid",
|
||
|
"name": "name",
|
||
|
"in": "path",
|
||
|
"required": true
|
||
|
}
|
||
|
],
|
||
|
"responses": {
|
||
|
"200": {
|
||
|
"description": "{\"ok\":true}"
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
},
|
||
|
"/v2/node/{name}/unschedulable": {
|
||
|
"put": {
|
||
|
"description": "make node unschedulable",
|
||
|
"produces": [
|
||
|
"application/json"
|
||
|
],
|
||
|
"tags": [
|
||
|
"v2"
|
||
|
],
|
||
|
"summary": "使节点不可调度",
|
||
|
"operationId": "Cordon",
|
||
|
"parameters": [
|
||
|
{
|
||
|
"type": "string",
|
||
|
"format": "string",
|
||
|
"description": "nodeuid",
|
||
|
"name": "name",
|
||
|
"in": "path",
|
||
|
"required": true
|
||
|
}
|
||
|
],
|
||
|
"responses": {
|
||
|
"200": {
|
||
|
"description": "{\"ok\":true}"
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
},
|
||
|
"/v2/node/{node}": {
|
||
|
"put": {
|
||
|
"description": "add node",
|
||
|
"produces": [
|
||
|
"application/json"
|
||
|
],
|
||
|
"tags": [
|
||
|
"v2"
|
||
|
],
|
||
|
"summary": "重新上线计算节点",
|
||
|
"operationId": "AddNode",
|
||
|
"parameters": [
|
||
|
{
|
||
|
"type": "string",
|
||
|
"format": "string",
|
||
|
"description": "nodeuid",
|
||
|
"name": "name",
|
||
|
"in": "path",
|
||
|
"required": true
|
||
|
}
|
||
|
],
|
||
|
"responses": {
|
||
|
"200": {
|
||
|
"description": "{\"ok\":true}"
|
||
|
}
|
||
|
}
|
||
|
},
|
||
|
"post": {
|
||
|
"description": "update",
|
||
|
"produces": [
|
||
|
"application/json"
|
||
|
],
|
||
|
"tags": [
|
||
|
"v2"
|
||
|
],
|
||
|
"summary": "更新node",
|
||
|
"operationId": "UpdateNode",
|
||
|
"parameters": [
|
||
|
{
|
||
|
"type": "string",
|
||
|
"format": "string",
|
||
|
"description": "nodeuid",
|
||
|
"name": "name",
|
||
|
"in": "path",
|
||
|
"required": true
|
||
|
},
|
||
|
{
|
||
|
"type": "string",
|
||
|
"format": "string",
|
||
|
"description": "[{\"uuid\": \"ccc\", \"Status\":\"create\",\"host_name\": \"10.0.55.73\", \"internal_ip\": \"10.0.55.73\", \"external_ip\": \"10.0.55.73\", \"available_memory\": 16267956, \"available_cpu\": 4, \"role\": \"\", \"labels\": {\"key1\": \"value1\"}, \"unschedulable\": false},{}]",
|
||
|
"in": "body",
|
||
|
"required": true
|
||
|
}
|
||
|
],
|
||
|
"responses": {
|
||
|
"200": {
|
||
|
"description": "{\"ok\":true}"
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
},
|
||
|
"/v2/node/{node}/down": {
|
||
|
"post": {
|
||
|
"description": "offline node",
|
||
|
"produces": [
|
||
|
"application/json"
|
||
|
],
|
||
|
"tags": [
|
||
|
"v2"
|
||
|
],
|
||
|
"summary": "下线计算节点",
|
||
|
"operationId": "DeleteNode",
|
||
|
"parameters": [
|
||
|
{
|
||
|
"type": "string",
|
||
|
"format": "string",
|
||
|
"description": "nodeuid",
|
||
|
"name": "name",
|
||
|
"in": "path",
|
||
|
"required": true
|
||
|
}
|
||
|
],
|
||
|
"responses": {
|
||
|
"200": {
|
||
|
"description": "{\"ok\":true}"
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|