func TestDoRequestNewWayObj(t *testing.T) { reqObj := &api.Pod{JSONBase: api.JSONBase{ID: "foo"}} reqBodyExpected, _ := api.Encode(reqObj) expectedObj := &api.Service{Port: 12345} expectedBody, _ := api.Encode(expectedObj) fakeHandler := util.FakeHandler{ StatusCode: 200, ResponseBody: string(expectedBody), T: t, } testServer := httptest.NewServer(&fakeHandler) auth := AuthInfo{User: "******", Password: "******"} c := NewOrDie(testServer.URL, &auth) obj, err := c.Verb("POST"). Path("foo/bar"). Path("baz"). SelectorParam("labels", labels.Set{"name": "foo"}.AsSelector()). Timeout(time.Second). Body(reqObj). Do().Get() if err != nil { t.Errorf("Unexpected error: %v %#v", err, err) return } if obj == nil { t.Error("nil obj") } else if !reflect.DeepEqual(obj, expectedObj) { t.Errorf("Expected: %#v, got %#v", expectedObj, obj) } tmpStr := string(reqBodyExpected) fakeHandler.ValidateRequest(t, "/api/v1beta1/foo/bar/baz?labels=name%3Dfoo", "POST", &tmpStr) if fakeHandler.RequestReceived.Header["Authorization"] == nil { t.Errorf("Request is missing authorization header: %#v", *fakeHandler.RequestReceived) } }
func TestAtomicUpdate(t *testing.T) { fakeClient := MakeFakeEtcdClient(t) fakeClient.TestIndex = true helper := EtcdHelper{fakeClient} // Create a new node. fakeClient.ExpectNotFoundGet("/some/key") obj := TestResource{JSONBase: api.JSONBase{ID: "foo"}, Value: 1} err := helper.AtomicUpdate("/some/key", &TestResource{}, func(in interface{}) (interface{}, error) { return obj, nil }) if err != nil { t.Errorf("Unexpected error %#v", err) } data, err := api.Encode(obj) if err != nil { t.Errorf("Unexpected error %#v", err) } expect := string(data) got := fakeClient.Data["/some/key"].R.Node.Value if expect != got { t.Errorf("Wanted %v, got %v", expect, got) } return // Update an existing node. callbackCalled := false objUpdate := &TestResource{JSONBase: api.JSONBase{ID: "foo"}, Value: 2} err = helper.AtomicUpdate("/some/key", &TestResource{}, func(in interface{}) (interface{}, error) { callbackCalled = true if in.(*TestResource).Value != 1 { t.Errorf("Callback input was not current set value") } return objUpdate, nil }) if err != nil { t.Errorf("Unexpected error %#v", err) } data, err = api.Encode(objUpdate) if err != nil { t.Errorf("Unexpected error %#v", err) } expect = string(data) got = fakeClient.Data["/some/key"].R.Node.Value if expect != got { t.Errorf("Wanted %v, got %v", expect, got) } if !callbackCalled { t.Errorf("tryUpdate callback should have been called.") } }
func TestDoRequestNewWayFile(t *testing.T) { reqObj := &api.Pod{JSONBase: api.JSONBase{ID: "foo"}} reqBodyExpected, err := api.Encode(reqObj) if err != nil { t.Errorf("unexpected error: %v", err) } file, err := ioutil.TempFile("", "foo") if err != nil { t.Errorf("unexpected error: %v", err) } _, err = file.Write(reqBodyExpected) if err != nil { t.Errorf("unexpected error: %v", err) } expectedObj := &api.Service{Port: 12345} expectedBody, _ := api.Encode(expectedObj) fakeHandler := util.FakeHandler{ StatusCode: 200, ResponseBody: string(expectedBody), T: t, } testServer := httptest.NewServer(&fakeHandler) auth := AuthInfo{User: "******", Password: "******"} s := New(testServer.URL, &auth) obj, err := s.Verb("POST"). Path("foo/bar"). Path("baz"). ParseSelector("name=foo"). Timeout(time.Second). Body(file.Name()). Do().Get() if err != nil { t.Errorf("Unexpected error: %v %#v", err, err) return } if obj == nil { t.Error("nil obj") } else if !reflect.DeepEqual(obj, expectedObj) { t.Errorf("Expected: %#v, got %#v", expectedObj, obj) } tmpStr := string(reqBodyExpected) fakeHandler.ValidateRequest(t, "/api/v1beta1/foo/bar/baz", "POST", &tmpStr) if fakeHandler.RequestReceived.URL.RawQuery != "labels=name%3Dfoo" { t.Errorf("Unexpected query: %v", fakeHandler.RequestReceived.URL.RawQuery) } if fakeHandler.RequestReceived.Header["Authorization"] == nil { t.Errorf("Request is missing authorization header: %#v", *fakeHandler.RequestReceived) } }
func TestDoRequestAcceptedSuccess(t *testing.T) { status := api.Status{Status: api.StatusSuccess} expectedBody, _ := api.Encode(status) fakeHandler := util.FakeHandler{ StatusCode: 202, ResponseBody: string(expectedBody), T: t, } testServer := httptest.NewTLSServer(&fakeHandler) request, _ := http.NewRequest("GET", testServer.URL+"/foo/bar", nil) auth := AuthInfo{User: "******", Password: "******"} c := New(testServer.URL, &auth) body, err := c.doRequest(request) if request.Header["Authorization"] == nil { t.Errorf("Request is missing authorization header: %#v", *request) } if err != nil { t.Errorf("Unexpected error %#v", err) } statusOut, err := api.Decode(body) if err != nil { t.Errorf("Unexpected error %#v", err) } if !reflect.DeepEqual(&status, statusOut) { t.Errorf("Unexpected mis-match. Expected %#v. Saw %#v", status, statusOut) } fakeHandler.ValidateRequest(t, "/foo/bar", "GET", nil) }
func TestHandleWatchResponseDelete(t *testing.T) { body, _ := api.Encode(makePodList(2)) fakeHandler := util.FakeHandler{ StatusCode: 200, ResponseBody: string(body), } testServer := httptest.NewTLSServer(&fakeHandler) client := client.New(testServer.URL, nil) fakePodControl := FakePodControl{} manager := MakeReplicationManager(nil, client) manager.podControl = &fakePodControl controller := makeReplicationController(2) // TODO: fixme when etcd writing uses api.Encode data, err := json.Marshal(controller) if err != nil { t.Errorf("Unexpected error: %v", err) } controllerOut, err := manager.handleWatchResponse(&etcd.Response{ Action: "delete", PrevNode: &etcd.Node{ Value: string(data), }, }) if err != nil { t.Errorf("Unexpected error: %#v", err) } if !reflect.DeepEqual(controller, *controllerOut) { t.Errorf("Unexpected mismatch. Expected %#v, Saw: %#v", controller, controllerOut) } }
// PrintObj is an implementation of ResourcePrinter.PrintObj which simply writes the object to the Writer. func (i *IdentityPrinter) PrintObj(obj interface{}, output io.Writer) error { data, err := api.Encode(obj) if err != nil { return err } return i.Print(data, output) }
func TestReadme(t *testing.T) { path := "../README.md" data, err := ioutil.ReadFile(path) if err != nil { t.Fatalf("Unable to read file: %v", err) } match := jsonRegexp.FindStringSubmatch(string(data)) if match == nil { return } for _, json := range match[1:] { expectedType := &api.Pod{} if err := api.DecodeInto([]byte(json), expectedType); err != nil { t.Errorf("%s did not decode correctly: %v\n%s", path, err, string(data)) return } if errors := validateObject(expectedType); len(errors) > 0 { t.Errorf("%s did not validate correctly: %v", path, errors) } encoded, err := api.Encode(expectedType) if err != nil { t.Errorf("Could not encode object: %v", err) continue } t.Logf("Found pod %s\n%s", json, encoded) } }
func TestWatchInterpretation_ListDelete(t *testing.T) { called := false w := newEtcdWatcher(true, func(interface{}) bool { called = true return true }) pod := &api.Pod{JSONBase: api.JSONBase{ID: "foo"}} podBytes, _ := api.Encode(pod) go w.sendResult(&etcd.Response{ Action: "delete", PrevNode: &etcd.Node{ Nodes: etcd.Nodes{ { Value: string(podBytes), }, }, }, }) got := <-w.outgoing if e, a := watch.Deleted, got.Type; e != a { t.Errorf("Expected %v, got %v", e, a) } if e, a := pod, got.Object; !reflect.DeepEqual(e, a) { t.Errorf("Expected %v, got %v", e, a) } if !called { t.Errorf("filter never called") } }
func TestDoRequestAccepted(t *testing.T) { status := api.Status{Status: api.StatusWorking} expectedBody, _ := api.Encode(status) fakeHandler := util.FakeHandler{ StatusCode: 202, ResponseBody: string(expectedBody), T: t, } testServer := httptest.NewTLSServer(&fakeHandler) request, _ := http.NewRequest("GET", testServer.URL+"/foo/bar", nil) auth := AuthInfo{User: "******", Password: "******"} c := New(testServer.URL, &auth) body, err := c.doRequest(request) if request.Header["Authorization"] == nil { t.Errorf("Request is missing authorization header: %#v", *request) } if err == nil { t.Error("Unexpected non-error") return } se, ok := err.(*StatusErr) if !ok { t.Errorf("Unexpected kind of error: %#v", err) return } if !reflect.DeepEqual(se.Status, status) { t.Errorf("Unexpected status: %#v", se.Status) } if body != nil { t.Errorf("Expected nil body, but saw: '%s'", body) } fakeHandler.ValidateRequest(t, "/foo/bar", "GET", nil) }
func TestCreate(t *testing.T) { simpleStorage := &SimpleRESTStorage{} handler := New(map[string]RESTStorage{ "foo": simpleStorage, }, "/prefix/version") handler.asyncOpWait = 0 server := httptest.NewServer(handler) client := http.Client{} simple := Simple{ Name: "foo", } data, _ := api.Encode(simple) request, err := http.NewRequest("POST", server.URL+"/prefix/version/foo", bytes.NewBuffer(data)) expectNoError(t, err) response, err := client.Do(request) expectNoError(t, err) if response.StatusCode != http.StatusAccepted { t.Errorf("Unexpected response %#v", response) } var itemOut api.Status body, err := extractBody(response, &itemOut) expectNoError(t, err) if itemOut.Status != api.StatusWorking || itemOut.Details == "" { t.Errorf("Unexpected status: %#v (%s)", itemOut, string(body)) } }
// Body makes the request use obj as the body. Optional. // If obj is a string, try to read a file of that name. // If obj is a []byte, send it directly. // Otherwise, assume obj is an api type and marshall it correctly. func (r *Request) Body(obj interface{}) *Request { if r.err != nil { return r } switch t := obj.(type) { case string: data, err := ioutil.ReadFile(t) if err != nil { r.err = err return r } r.body = bytes.NewBuffer(data) case []byte: r.body = bytes.NewBuffer(t) case io.Reader: r.body = obj.(io.Reader) default: data, err := api.Encode(obj) if err != nil { r.err = err return r } r.body = bytes.NewBuffer(data) } return r }
func TestCreateNotFound(t *testing.T) { handler := New(map[string]RESTStorage{ "simple": &SimpleRESTStorage{ // storage.Create can fail with not found error in theory. // See https://github.com/GoogleCloudPlatform/kubernetes/pull/486#discussion_r15037092. errors: map[string]error{"create": NewNotFoundErr("simple", "id")}, }, }, "/prefix/version") server := httptest.NewServer(handler) client := http.Client{} simple := Simple{Name: "foo"} data, _ := api.Encode(simple) request, err := http.NewRequest("POST", server.URL+"/prefix/version/simple", bytes.NewBuffer(data)) if err != nil { t.Errorf("unexpected error: %v", err) } response, err := client.Do(request) if err != nil { t.Errorf("unexpected error: %v", err) } if response.StatusCode != http.StatusNotFound { t.Errorf("Unexpected response %#v", response) } }
func TestUpdateMissing(t *testing.T) { storage := map[string]RESTStorage{} ID := "id" simpleStorage := SimpleRESTStorage{ errors: map[string]error{"update": NewNotFoundErr("simple", ID)}, } storage["simple"] = &simpleStorage handler := New(storage, "/prefix/version") server := httptest.NewServer(handler) item := Simple{ Name: "bar", } body, err := api.Encode(item) if err != nil { t.Errorf("unexpected error: %v", err) } client := http.Client{} request, err := http.NewRequest("PUT", server.URL+"/prefix/version/simple/"+ID, bytes.NewReader(body)) response, err := client.Do(request) if err != nil { t.Errorf("unexpected error: %v", err) } if response.StatusCode != http.StatusNotFound { t.Errorf("Unexpected response %#v", response) } }
func TestUpdate(t *testing.T) { storage := map[string]RESTStorage{} simpleStorage := SimpleRESTStorage{} ID := "id" storage["simple"] = &simpleStorage handler := New(storage, "/prefix/version") server := httptest.NewServer(handler) item := Simple{ Name: "bar", } body, err := api.Encode(item) if err != nil { t.Errorf("unexpected error: %v", err) } client := http.Client{} request, err := http.NewRequest("PUT", server.URL+"/prefix/version/simple/"+ID, bytes.NewReader(body)) _, err = client.Do(request) if err != nil { t.Errorf("unexpected error: %v", err) } if simpleStorage.updated.Name != item.Name { t.Errorf("Unexpected update value %#v, expected %#v.", simpleStorage.updated, item) } }
func TestPolling(t *testing.T) { objects := []interface{}{ &api.Status{Status: api.StatusWorking, Details: "1234"}, &api.Status{Status: api.StatusWorking, Details: "1234"}, &api.Status{Status: api.StatusWorking, Details: "1234"}, &api.Status{Status: api.StatusWorking, Details: "1234"}, &api.Status{Status: api.StatusSuccess}, } callNumber := 0 testServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { data, err := api.Encode(objects[callNumber]) if err != nil { t.Errorf("Unexpected encode error") } callNumber++ w.Write(data) })) auth := AuthInfo{User: "******", Password: "******"} s := New(testServer.URL, &auth) trials := []func(){ func() { // Check that we do indeed poll when asked to. obj, err := s.Get().PollPeriod(5 * time.Millisecond).Do().Get() if err != nil { t.Errorf("Unexpected error: %v %#v", err, err) return } if s, ok := obj.(*api.Status); !ok || s.Status != api.StatusSuccess { t.Errorf("Unexpected return object: %#v", obj) return } if callNumber != len(objects) { t.Errorf("Unexpected number of calls: %v", callNumber) } }, func() { // Check that we don't poll when asked not to. obj, err := s.Get().PollPeriod(0).Do().Get() if err == nil { t.Errorf("Unexpected non error: %v", obj) return } if se, ok := err.(*StatusErr); !ok || se.Status.Status != api.StatusWorking { t.Errorf("Unexpected kind of error: %#v", err) return } if callNumber != 1 { t.Errorf("Unexpected number of calls: %v", callNumber) } }, } for _, f := range trials { callNumber = 0 f() } }
func body(obj interface{}, raw *string) *string { if obj != nil { bs, _ := api.Encode(obj) body := string(bs) return &body } return raw }
func (server *ApiServer) write(statusCode int, object interface{}, w http.ResponseWriter) { w.WriteHeader(statusCode) output, err := api.Encode(object) if err != nil { server.error(err, w) return } w.Write(output) }
func (s *ProxyServer) doError(w http.ResponseWriter, err error) { w.WriteHeader(http.StatusInternalServerError) w.Header().Add("Content-type", "application/json") data, _ := api.Encode(api.Status{ Status: api.StatusFailure, Details: fmt.Sprintf("internal error: %#v", err), }) w.Write(data) }
func TestCreateReplica(t *testing.T) { body, _ := api.Encode(api.Pod{}) fakeHandler := util.FakeHandler{ StatusCode: 200, ResponseBody: string(body), } testServer := httptest.NewTLSServer(&fakeHandler) client := client.New(testServer.URL, nil) podControl := RealPodControl{ kubeClient: client, } controllerSpec := api.ReplicationController{ JSONBase: api.JSONBase{ Kind: "ReplicationController", }, DesiredState: api.ReplicationControllerState{ PodTemplate: api.PodTemplate{ DesiredState: api.PodState{ Manifest: api.ContainerManifest{ Containers: []api.Container{ { Image: "foo/bar", }, }, }, }, Labels: map[string]string{ "name": "foo", "type": "production", }, }, }, } podControl.createReplica(controllerSpec) expectedPod := api.Pod{ JSONBase: api.JSONBase{ Kind: "Pod", APIVersion: "v1beta1", }, Labels: controllerSpec.DesiredState.PodTemplate.Labels, DesiredState: controllerSpec.DesiredState.PodTemplate.DesiredState, } fakeHandler.ValidateRequest(t, makeURL("/pods"), "POST", nil) actualPod := api.Pod{} if err := json.Unmarshal([]byte(fakeHandler.RequestBody), &actualPod); err != nil { t.Errorf("Unexpected error: %#v", err) } if !reflect.DeepEqual(expectedPod, actualPod) { t.Logf("Body: %s", fakeHandler.RequestBody) t.Errorf("Unexpected mismatch. Expected\n %#v,\n Got:\n %#v", expectedPod, actualPod) } }
func TestOpGet(t *testing.T) { simpleStorage := &SimpleRESTStorage{} handler := New(map[string]RESTStorage{ "foo": simpleStorage, }, "/prefix/version") handler.asyncOpWait = 0 server := httptest.NewServer(handler) client := http.Client{} simple := Simple{ Name: "foo", } data, err := api.Encode(simple) t.Log(string(data)) if err != nil { t.Errorf("unexpected error: %v", err) } request, err := http.NewRequest("POST", server.URL+"/prefix/version/foo", bytes.NewBuffer(data)) if err != nil { t.Errorf("unexpected error: %v", err) } response, err := client.Do(request) if err != nil { t.Errorf("unexpected error: %v", err) } if response.StatusCode != http.StatusAccepted { t.Errorf("Unexpected response %#v", response) } var itemOut api.Status body, err := extractBody(response, &itemOut) if err != nil { t.Errorf("unexpected error: %v", err) } if itemOut.Status != api.StatusWorking || itemOut.Details == "" { t.Errorf("Unexpected status: %#v (%s)", itemOut, string(body)) } req2, err := http.NewRequest("GET", server.URL+"/prefix/version/operations/"+itemOut.Details, nil) if err != nil { t.Errorf("unexpected error: %v", err) } _, err = client.Do(req2) if err != nil { t.Errorf("unexpected error: %v", err) } if response.StatusCode != http.StatusAccepted { t.Errorf("Unexpected response %#v", response) } }
func (server *APIServer) write(statusCode int, object interface{}, w http.ResponseWriter) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(statusCode) output, err := api.Encode(object) if err != nil { server.error(err, w) return } w.Write(output) }
// writeJSON renders an object as JSON to the response func writeJSON(statusCode int, object interface{}, w http.ResponseWriter) { output, err := api.Encode(object) if err != nil { internalError(err, w) return } w.Header().Set("Content-Type", "application/json") w.WriteHeader(statusCode) w.Write(output) }
// ToWireFormat takes input 'data' as either json or yaml, checks that it parses as the // appropriate object type, and returns json for sending to the API or an error. func (p *Parser) ToWireFormat(data []byte, storage string) ([]byte, error) { prototypeType, found := p.storageToType[storage] if !found { return nil, fmt.Errorf("unknown storage type: %v", storage) } obj := reflect.New(prototypeType).Interface() err := api.DecodeInto(data, obj) if err != nil { return nil, err } return api.Encode(obj) }
// SetObj marshals obj via json, and stores under key. Will do an // atomic update if obj's ResourceVersion field is set. func (h *EtcdHelper) SetObj(key string, obj interface{}) error { data, err := api.Encode(obj) if err != nil { return err } if jsonBase, err := api.FindJSONBaseRO(obj); err == nil && jsonBase.ResourceVersion != 0 { _, err = h.Client.CompareAndSwap(key, string(data), 0, "", jsonBase.ResourceVersion) return err // err is shadowed! } // TODO: when client supports atomic creation, integrate this with the above. _, err = h.Client.Set(key, string(data), 0) return err }
func TestSyncCreate(t *testing.T) { storage := SimpleRESTStorage{ injectedFunction: func(obj interface{}) (interface{}, error) { time.Sleep(5 * time.Millisecond) return obj, nil }, } handler := New(map[string]RESTStorage{ "foo": &storage, }, "/prefix/version") server := httptest.NewServer(handler) client := http.Client{} simple := Simple{ Name: "foo", } data, _ := api.Encode(simple) request, err := http.NewRequest("POST", server.URL+"/prefix/version/foo?sync=true", bytes.NewBuffer(data)) if err != nil { t.Errorf("unexpected error: %v", err) } wg := sync.WaitGroup{} wg.Add(1) var response *http.Response go func() { response, err = client.Do(request) wg.Done() }() wg.Wait() if err != nil { t.Errorf("unexpected error: %v", err) } var itemOut Simple body, err := extractBody(response, &itemOut) if err != nil { t.Errorf("unexpected error: %v", err) } if !reflect.DeepEqual(itemOut, simple) { t.Errorf("Unexpected data: %#v, expected %#v (%s)", itemOut, simple, string(body)) } if response.StatusCode != http.StatusOK { t.Errorf("Unexpected status: %d, Expected: %d, %#v", response.StatusCode, http.StatusOK, response) } }
func TestOperationsList(t *testing.T) { simpleStorage := &SimpleRESTStorage{} handler := New(map[string]RESTStorage{ "foo": simpleStorage, }, "/prefix/version") handler.asyncOpWait = 0 server := httptest.NewServer(handler) client := http.Client{} simple := Simple{ Name: "foo", } data, err := api.Encode(simple) if err != nil { t.Errorf("unexpected error: %v", err) } response, err := client.Post(server.URL+"/prefix/version/foo", "application/json", bytes.NewBuffer(data)) if err != nil { t.Errorf("unexpected error: %v", err) } if response.StatusCode != http.StatusAccepted { t.Errorf("Unexpected response %#v", response) } response, err = client.Get(server.URL + "/prefix/version/operations") if err != nil { t.Errorf("unexpected error: %v", err) } if response.StatusCode != http.StatusOK { t.Fatalf("unexpected status code %#v", response) } body, err := ioutil.ReadAll(response.Body) if err != nil { t.Errorf("unexpected error: %v", err) } obj, err := api.Decode(body) if err != nil { t.Errorf("unexpected error: %v", err) } oplist, ok := obj.(*api.ServerOpList) if !ok { t.Fatalf("expected ServerOpList, got %#v", obj) } if len(oplist.Items) != 1 { t.Errorf("expected 1 operation, got %#v", obj) } }
func TestEncode_Ptr(t *testing.T) { pod := &api.Pod{ Labels: map[string]string{"name": "foo"}, } obj := interface{}(pod) data, err := api.Encode(obj) obj2, err2 := api.Decode(data) if err != nil || err2 != nil { t.Fatalf("Failure: '%v' '%v'", err, err2) } if _, ok := obj2.(*api.Pod); !ok { t.Fatalf("Got wrong type") } if !reflect.DeepEqual(obj2, pod) { t.Errorf("Expected:\n %#v,\n Got:\n %#v", &pod, obj2) } }
func TestSetObj(t *testing.T) { obj := api.Pod{JSONBase: api.JSONBase{ID: "foo"}} fakeClient := MakeFakeEtcdClient(t) helper := EtcdHelper{fakeClient} err := helper.SetObj("/some/key", obj) if err != nil { t.Errorf("Unexpected error %#v", err) } data, err := api.Encode(obj) if err != nil { t.Errorf("Unexpected error %#v", err) } expect := string(data) got := fakeClient.Data["/some/key"].R.Node.Value if expect != got { t.Errorf("Wanted %v, got %v", expect, got) } }
func TestExtractJson(t *testing.T) { mockRegistry := MockPodRegistry{} storage := PodRegistryStorage{ registry: &mockRegistry, } pod := api.Pod{ JSONBase: api.JSONBase{ ID: "foo", }, } body, err := api.Encode(&pod) expectNoError(t, err) podOut, err := storage.Extract(body) expectNoError(t, err) if !reflect.DeepEqual(pod, podOut) { t.Errorf("Expected %#v, found %#v", pod, podOut) } }
func TestExtractControllerJson(t *testing.T) { mockRegistry := MockControllerRegistry{} storage := ControllerRegistryStorage{ registry: &mockRegistry, } controller := api.ReplicationController{ JSONBase: api.JSONBase{ ID: "foo", }, } body, err := api.Encode(&controller) expectNoError(t, err) controllerOut, err := storage.Extract(body) expectNoError(t, err) if !reflect.DeepEqual(controller, controllerOut) { t.Errorf("Expected %#v, found %#v", controller, controllerOut) } }