SetHeader() public method

Sets the value of an HTTP Response Header. Many standard headers are defined in WebServer.HTTPHeader, but custom headers can always be manually set in case this is desired.

Headers are sent in the Header: Value format in the HTTP protocol.

public SetHeader ( string header, string value ) : void
header string /// The name of the header, for example: /// /// /// "My-Custom-Header" /// ///
value string /// The value of the header. ///
return void
Beispiel #1
0
        private void HandleRequest(WoopsaVerb verb, HTTPRequest request, HTTPResponse response)
        {
            try
            {
                // This is the first thing we do, that way even 404 errors have the right headers
                if (AllowCrossOrigin)
                {
                    // TODO: constantes symboliques
                    response.SetHeader("Access-Control-Allow-Origin", "*");
                }
                string result = null;
                ExecuteBeforeWoopsaModelAccess();
                try
                {
                    switch (verb)
                    {
                    case WoopsaVerb.Meta:
                        result = GetMetadata(request.Subroute);
                        break;

                    case WoopsaVerb.Read:
                        result = ReadValue(request.Subroute);
                        break;

                    case WoopsaVerb.Write:
                        result = WriteValue(request.Subroute, request.Body["value"]);
                        break;

                    case WoopsaVerb.Invoke:
                        result = InvokeMethod(request.Subroute, request.Body);
                        break;
                    }
                }
                finally
                {
                    ExecuteAfterWoopsaModelAccess();
                }
                response.SetHeader(HTTPHeader.ContentType, MIMETypes.Application.JSON);
                if (result != null)
                {
                    response.WriteString(result);
                }
            }
            catch (WoopsaNotFoundException e)
            {
                response.WriteError(HTTPStatusCode.NotFound, e.Message, WoopsaFormat.Serialize(e), MIMETypes.Application.JSON);
            }
            catch (WoopsaInvalidOperationException e)
            {
                response.WriteError(HTTPStatusCode.BadRequest, e.Message, WoopsaFormat.Serialize(e), MIMETypes.Application.JSON);
            }
            catch (WoopsaException e)
            {
                response.WriteError(HTTPStatusCode.InternalServerError, e.Message, WoopsaFormat.Serialize(e), MIMETypes.Application.JSON);
            }
            catch (Exception e)
            {
                response.WriteError(HTTPStatusCode.InternalServerError, e.Message, WoopsaFormat.Serialize(e), MIMETypes.Application.JSON);
            }
        }
        public void HandleRequest(HTTPRequest request, HTTPResponse response)
        {
            if (request.Subroute == "")
            {
                //If there really is no file requested, then we send a 404!
                response.WriteError(HTTPStatusCode.NotFound, "Not Found");
                return;
            }

            lock (_dictionary)
            {
                if (_dictionary.TryGetValue(request.Subroute, out MemoryStream resource))
                {
                    resource.Position = 0;
                    response.WriteStream(resource);
                    response.SetHeader("Cache-Control", "no-cache, no-store, must-revalidate");
                    response.SetHeader("Pragma", "no-cache");
                    response.SetHeader("Expires", "0");
                }
                else
                {
                    response.WriteError(HTTPStatusCode.NotFound, "Not Found");
                }
            }
        }
        private bool ServeEmbeddedResource(HTTPResponse response, Assembly assembly,
                                           string strippedResourceName)
        {
            string fullResourceName = FullResourceName(assembly, strippedResourceName);

            if (!string.IsNullOrEmpty(fullResourceName))
            {
                try
                {
                    using (Stream resourceStream = assembly.GetManifestResourceStream(fullResourceName))
                        if (resourceStream != null)
                        {
                            string extension = Path.GetExtension(strippedResourceName);
                            response.SetHeader(HTTPHeader.ContentType, MIMETypeMap.GetMIMEType(extension));
                            response.SetHeader(HTTPHeader.LastModified, File.GetLastWriteTime(assembly.Location).ToHTTPDate());
                            response.WriteStream(resourceStream);
                            return(true);
                        }
                }
                catch
                {
                }
            }
            return(false);
        }
Beispiel #4
0
        private void ServeFile(string filePath, HTTPResponse response)
        {
            string extension = Path.GetExtension(filePath);

            response.SetHeader(HTTPHeader.ContentType, MIMETypeMap.GetMIMEType(extension));
            response.SetHeader(HTTPHeader.LastModified, System.IO.File.GetLastWriteTime(filePath).ToHTTPDate());

            using (var stream = File.Open(filePath, FileMode.Open, FileAccess.Read, FileShare.Read))
                response.WriteStream(stream);
        }
Beispiel #5
0
 public bool Process(HTTPRequest request, HTTPResponse response)
 {
     response.SetHeader("Access-Control-Allow-Headers", "Authorization");
     // TODO : constante symbolique + déterminer si AllowCrossOrigin doit être utilisé ici
     response.SetHeader("Access-Control-Allow-Origin", "*");
     response.SetHeader("Access-Control-Allow-Credentials", "true");
     response.SetHeader("Access-Control-Max-Age", MaxAge.TotalSeconds.ToString(CultureInfo.InvariantCulture));
     // Make IE stop cacheing AJAX requests
     response.SetHeader("Cache-Control", "no-cache, no-store");
     return(true);
 }
Beispiel #6
0
        private void ServeFile(string filePath, HTTPResponse response)
        {
            string extension = Path.GetExtension(filePath);

            response.SetHeader(HTTPHeader.ContentType, MIMETypeMap.GetMIMEType(extension));
            response.SetHeader(HTTPHeader.LastModified, System.IO.File.GetLastWriteTime(filePath).ToHTTPDate());
            FileStream file = File.Open(filePath, FileMode.Open);

            response.WriteStream(file);
            file.Close();
        }
Beispiel #7
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="request"></param>
        /// <param name="response"></param>
        /// <param name="stream"></param>
        /// <returns>true if the request must be executed normally, false otherwise</returns>
        protected virtual bool HandleCorsRequest(HTTPRequest request, HTTPResponse response, Stream stream)
        {
            // 1. Prepare default values in event args
            CorsRequestArgs eventArgs = new Woopsa.CorsRequestArgs(request, response, stream);

            eventArgs.AccessControlMaxAgeValue = HTTPHeader.AccessControlMaxAgeDefaultValue;
            if (request.Headers.ContainsKey(HTTPHeader.AccessControlRequestHeaders))
            {
                eventArgs.AccessControlAllowHeadersValue = request.Headers[HTTPHeader.AccessControlRequestHeaders];
            }
            eventArgs.AccessControlAllowOriginValue = HTTPHeader.AccessControlAllowOriginDefaultValue;
            if (request.Headers.ContainsKey(HTTPHeader.AccessControlRequestMethod))
            {
                eventArgs.AccessControlAllowMethodsValue = HTTPHeader.AccessControlAllowMethodsDefaultValue;
            }
            eventArgs.IsPreflightCorsRequest = request.Method == HTTPMethod.OPTIONS;
            eventArgs.ExecuteRequest         = !eventArgs.IsPreflightCorsRequest;
            // 2. call event
            if (CorsRequest != null)
            {
                CorsRequest(this, eventArgs);
            }
            // 3. Set headers into response
            // AccessControlAllowOrigin must be set for simple and preflight CORS requests
            if (eventArgs.AccessControlAllowOriginValue != null)
            {
                response.SetHeader(HTTPHeader.AccessControlAllowOrigin,
                                   eventArgs.AccessControlAllowOriginValue);
            }
            if (eventArgs.IsPreflightCorsRequest)
            {
                // Set additional preflight CORS request headers
                if (eventArgs.AccessControlAllowHeadersValue != null)
                {
                    response.SetHeader(HTTPHeader.AccessControlAllowHeaders,
                                       eventArgs.AccessControlAllowHeadersValue);
                }
                if (eventArgs.AccessControlAllowMethodsValue != null)
                {
                    response.SetHeader(HTTPHeader.AccessControlAllowMethods,
                                       eventArgs.AccessControlAllowMethodsValue);
                }
                if (eventArgs.AccessControlMaxAgeValue != null)
                {
                    response.SetHeader(HTTPHeader.AccessControlMaxAge, eventArgs.AccessControlMaxAgeValue.Value.
                                       TotalSeconds.ToString(CultureInfo.InvariantCulture));
                }
            }
            return(eventArgs.ExecuteRequest);
        }
        public virtual bool Process(HTTPRequest request, HTTPResponse response)
        {
            string username;
            string password;
            bool   authenticated;

            _currentUserName = null;
            if (request.Headers.ContainsKey(HTTPHeader.Authorization))
            {
                string authString = request.Headers[HTTPHeader.Authorization].Split(' ')[1];
                authString = Encoding.GetEncoding("ISO-8859-1").GetString(Convert.FromBase64String(authString));
                string[] parts = authString.Split(':');
                username = parts[0];
                password = parts[1];
            }
            else
            {
                username = null;
                password = null;
            }
            authenticated = Authenticate(request, username, password);
            if (authenticated)
            {
                _currentUserName = username;
            }
            else
            {
                response.SetHeader(HTTPHeader.WWWAuthenticate, "Basic Realm=\"" + Realm + "\"");
                response.WriteError(HTTPStatusCode.Unauthorized, "Unauthorized");
            }
            return(authenticated);
        }
Beispiel #9
0
        protected virtual void HandleRequest(HTTPRequest request, HTTPResponse response, Stream stream)
        {
            bool executeRequest = true;

            response.SetHeader("Access-Control-Allow-Credentials", "true");
            if (request.Headers.ContainsKey(HTTPHeader.Origin))
            {
                executeRequest = HandleCorsRequest(request, response, stream);
            }
            if (executeRequest)
            {
                Routes.HandleRequest(request, response, stream);
            }
        }
Beispiel #10
0
        private void HandleClient(TcpClient client)
        {
            lock (_openTcpClients)
                _openTcpClients.Add(client);
            try
            {
                Stream stream = client.GetStream();
                try
                {
                    foreach (PreRouteProcessor processor in PreRouteProcessors)
                    {
                        stream = processor.ProcessStream(stream);
                    }
                    bool leaveOpen = true;
                    HTTPResponse response = null;
                    HTTPRequest request = null;
                    StreamReader reader = new StreamReader(stream, Encoding.UTF8, false, 4096);
                    try
                    {
                        while (leaveOpen && !_aborted)
                        {
                            response = new HTTPResponse();
                            /*
                                * Parse the first line of the HTTP Request
                                * Examples:
                                *      GET / HTTP/1.1
                                *      POST /submit HTTP/1.1
                                */
                            string requestString;
                            try
                            {
                                requestString = reader.ReadLine();
                            }
                            catch (Exception)
                            {
                                requestString = null;
                                leaveOpen = false;
                                break;
                            }
                            if (requestString == null)
                                break;

                            string[] parts = requestString.Split(' ');
                            if (parts.Length != 3)
                            {
                                throw new HandlingException(HTTPStatusCode.BadRequest, "Bad Request");
                            }
                            string method = parts[0].ToUpper();
                            string url = parts[1];
                            string version = parts[2].ToUpper();

                            //Check if the version is what we expect
                            if (version != "HTTP/1.1" && version != "HTTP/1.0")
                            {
                                throw new HandlingException(HTTPStatusCode.HttpVersionNotSupported, "HTTP Version Not Supported");
                            }

                            //Check if the method is supported
                            if (!_supportedMethods.ContainsKey(method))
                            {
                                throw new HandlingException(HTTPStatusCode.NotImplemented, method + " Method Not Implemented");
                            }
                            HTTPMethod httpMethod = _supportedMethods[method];

                            url = HttpUtility.UrlDecode(url);

                            //Build the request object
                            request = new HTTPRequest(httpMethod, url);

                            //Add all headers to the request object
                            FillHeaders(request, reader);

                            //Handle encoding for this request
                            Encoding clientEncoding = InferEncoding(request);

                            //Extract all the data from the URL (base and query)
                            ExtractQuery(request, clientEncoding);

                            //Extract and decode all the POST data
                            ExtractPOST(request, reader, clientEncoding);

                            bool keepAlive = false;
                            // According to spec, Keep-Alive is ON by default
                            if (version == "HTTP/1.1")
                                keepAlive = true;
                            if (request.Headers.ContainsKey(HTTPHeader.Connection))
                            {
                                if (request.Headers[HTTPHeader.Connection].ToLower().Equals("close"))
                                {
                                    keepAlive = false;
                                    response.SetHeader(HTTPHeader.Connection, "close");
                                }
                            }

                            //Keep-Alive can only work on a multithreaded server!
                            if (!keepAlive || !MultiThreaded)
                            {
                                leaveOpen = false;
                                response.SetHeader(HTTPHeader.Connection, "close");
                            }
                            //Pass this on to the route solver
                            OnLog(request, null);
                            Routes.HandleRequest(request, response, stream);
                            OnLog(request, response);
                        }
                    }
                    catch (HandlingException e)
                    {
                        if (response != null)
                        {
                            try
                            {
                                // try to return the response
                                response.WriteError(e.Status, e.ErrorMessage);
                                response.Respond(stream);
                            }
                            catch
                            {
                                // ignore silently if it is not posible
                            }
                            OnLog(request, response);
                        }
                    }
                    catch (ThreadAbortException)
                    {
                        // Do nothing, server is terminating
                    }
                    catch (Exception e)
                    {
                        if (response != null)
                        {
                            try
                            {
                                // try to return the response
                                response.WriteError(HTTPStatusCode.InternalServerError, "Internal Server Error. " + e.Message);
                                response.Respond(stream);
                            }
                            catch
                            {
                                // ignore silently if it is not posible
                            }
                            OnLog(request, response);
                        }
                    }
                    finally
                    {
                        reader.Close();
                    }
                }
                finally
                {
                    stream.Dispose();
                }
            }
            finally
            {
                lock (_openTcpClients)
                    _openTcpClients.Remove(client);
            }
        }
 public bool Process(HTTPRequest request, HTTPResponse response)
 {
     bool authenticated;
     _currentUserName = null;
     if (request.Headers.ContainsKey(HTTPHeader.Authorization))
     {
         string authString = request.Headers[HTTPHeader.Authorization].Split(' ')[1];
         authString = Encoding.GetEncoding("ISO-8859-1").GetString(Convert.FromBase64String(authString));
         string[] parts = authString.Split(':');
         string username = parts[0];
         string password = parts[1];
         authenticated = Authenticate(username, password);
         if (authenticated)
             _currentUserName = username;
     }
     else
         authenticated = false;
     if (!authenticated)
     {
         response.SetHeader(HTTPHeader.WWWAuthenticate, "Basic Realm=\"" + Realm + "\"");
         response.WriteError(HTTPStatusCode.Unauthorized, "Unauthorized");
     }
     return authenticated;
 }
 private bool ServeEmbeddedResource(HTTPResponse response, Assembly assembly,
     string strippedResourceName)
 {
     string fullResourceName = FullResourceName(assembly, strippedResourceName);
     if (!string.IsNullOrEmpty(fullResourceName))
         try
         {
             using (Stream resourceStream = assembly.GetManifestResourceStream(fullResourceName))
                 if (resourceStream != null)
                 {
                     string extension = Path.GetExtension(strippedResourceName);
                     response.SetHeader(HTTPHeader.ContentType, MIMETypeMap.GetMIMEType(extension));
                     response.SetHeader(HTTPHeader.LastModified, File.GetLastWriteTime(assembly.Location).ToHTTPDate());
                     response.WriteStream(resourceStream);
                     return true;
                 }
         }
         catch
         {
         }
     return false;
 }
Beispiel #13
0
 private void HandleRequest(WoopsaVerb verb, HTTPRequest request, HTTPResponse response)
 {
     try
     {
         // This is the first thing we do, that way even 404 errors have the right headers
         if (AllowCrossOrigin)
             // TODO: constantes symboliques
             response.SetHeader("Access-Control-Allow-Origin", "*");
         string result = null;
         ExecuteBeforeWoopsaModelAccess();
         try
         {
             switch (verb)
             {
                 case WoopsaVerb.Meta:
                     result = GetMetadata(request.Subroute);
                     break;
                 case WoopsaVerb.Read:
                     result = ReadValue(request.Subroute);
                     break;
                 case WoopsaVerb.Write:
                     result = WriteValue(request.Subroute, request.Body["value"]);
                     break;
                 case WoopsaVerb.Invoke:
                     result = InvokeMethod(request.Subroute, request.Body);
                     break;
             }
         }
         finally
         {
             ExecuteAfterWoopsaModelAccess();
         }
         response.SetHeader(HTTPHeader.ContentType, MIMETypes.Application.JSON);
         if (result != null)
             response.WriteString(result);
     }
     catch (WoopsaNotFoundException e)
     {
         response.WriteError(HTTPStatusCode.NotFound, e.Message, WoopsaFormat.Serialize(e), MIMETypes.Application.JSON);
     }
     catch (WoopsaInvalidOperationException e)
     {
         response.WriteError(HTTPStatusCode.BadRequest, e.Message, WoopsaFormat.Serialize(e), MIMETypes.Application.JSON);
     }
     catch (WoopsaException e)
     {
         response.WriteError(HTTPStatusCode.InternalServerError, e.Message, WoopsaFormat.Serialize(e), MIMETypes.Application.JSON);
     }
     catch (Exception e)
     {
         response.WriteError(HTTPStatusCode.InternalServerError, e.Message, WoopsaFormat.Serialize(e), MIMETypes.Application.JSON);
     }
 }
Beispiel #14
0
 public bool Process(HTTPRequest request, HTTPResponse response)
 {
     response.SetHeader("Access-Control-Allow-Headers", "Authorization");
     // TODO : constante symbolique + déterminer si AllowCrossOrigin doit être utilisé ici
     response.SetHeader("Access-Control-Allow-Origin", "*");
     response.SetHeader("Access-Control-Allow-Credentials", "true");
     response.SetHeader("Access-Control-Max-Age", MaxAge.TotalSeconds.ToString(CultureInfo.InvariantCulture));
     // Make IE stop cacheing AJAX requests
     response.SetHeader("Cache-Control", "no-cache, no-store");
     return true;
 }
Beispiel #15
0
        private void HandleRequest(WoopsaVerb verb, HTTPRequest request, HTTPResponse response)
        {
            try
            {
                _currentWoopsaServer = this;
                try
                {
                    string result = null;
                    ExecuteBeforeWoopsaModelAccess();
                    try
                    {
                        switch (verb)
                        {
                        case WoopsaVerb.Meta:
                            result = GetMetadata(request.Subroute);
                            break;

                        case WoopsaVerb.Read:
                            result = ReadValue(request.Subroute);
                            break;

                        case WoopsaVerb.Write:
                            result = WriteValue(request.Subroute, request.Body["value"]);
                            break;

                        case WoopsaVerb.Invoke:
                            result = InvokeMethod(request.Subroute, request.Body);
                            break;
                        }
                    }
                    finally
                    {
                        ExecuteAfterWoopsaModelAccess();
                    }
                    response.SetHeader(HTTPHeader.ContentType, MIMETypes.Application.JSON);
                    if (result != null)
                    {
                        response.WriteString(result);
                    }
                }
                finally
                {
                    _currentWoopsaServer = null;
                }
            }
            catch (WoopsaNotFoundException e)
            {
                response.WriteError(HTTPStatusCode.NotFound, e.GetFullMessage(), e.Serialize(), MIMETypes.Application.JSON);
                OnHandledException(e);
            }
            catch (WoopsaInvalidOperationException e)
            {
                response.WriteError(HTTPStatusCode.BadRequest, e.GetFullMessage(), e.Serialize(), MIMETypes.Application.JSON);
                OnHandledException(e);
            }
            catch (WoopsaException e)
            {
                response.WriteError(HTTPStatusCode.InternalServerError, e.GetFullMessage(), e.Serialize(), MIMETypes.Application.JSON);
                OnHandledException(e);
            }
            catch (Exception e)
            {
                response.WriteError(HTTPStatusCode.InternalServerError, e.GetFullMessage(), e.Serialize(), MIMETypes.Application.JSON);
                OnHandledException(e);
            }
        }
 private void ServeFile(string filePath, HTTPResponse response)
 {
     string extension = Path.GetExtension(filePath);
     response.SetHeader(HTTPHeader.ContentType, MIMETypeMap.GetMIMEType(extension));
     response.SetHeader(HTTPHeader.LastModified, System.IO.File.GetLastWriteTime(filePath).ToHTTPDate());
     FileStream file = File.Open(filePath, FileMode.Open);
     response.WriteStream(file);
     file.Close();
 }
Beispiel #17
0
        private void HandleClient(TcpClient client)
        {
            lock (_openTcpClients)
                _openTcpClients.Add(client);
            try
            {
                Stream stream = client.GetStream();
                try
                {
                    foreach (PreRouteProcessor processor in PreRouteProcessors)
                    {
                        stream = processor.ProcessStream(stream);
                    }
                    bool         leaveOpen = true;
                    HTTPResponse response  = null;
                    HTTPRequest  request   = null;
                    StreamReader reader    = new StreamReader(stream, Encoding.UTF8, false, 4096);
                    try
                    {
                        while (leaveOpen && !_aborted)
                        {
                            response = new HTTPResponse();

                            /*
                             * Parse the first line of the HTTP Request
                             * Examples:
                             *      GET / HTTP/1.1
                             *      POST /submit HTTP/1.1
                             */
                            string requestString;
                            try
                            {
                                requestString = reader.ReadLine();
                            }
                            catch (Exception)
                            {
                                requestString = null;
                                leaveOpen     = false;
                                break;
                            }
                            if (requestString == null)
                            {
                                break;
                            }

                            string[] parts = requestString.Split(' ');
                            if (parts.Length != 3)
                            {
                                throw new HandlingException(HTTPStatusCode.BadRequest, "Bad Request");
                            }
                            string method  = parts[0].ToUpper();
                            string url     = parts[1];
                            string version = parts[2].ToUpper();

                            //Check if the version is what we expect
                            if (version != "HTTP/1.1" && version != "HTTP/1.0")
                            {
                                throw new HandlingException(HTTPStatusCode.HttpVersionNotSupported, "HTTP Version Not Supported");
                            }

                            //Check if the method is supported
                            if (!_supportedMethods.ContainsKey(method))
                            {
                                throw new HandlingException(HTTPStatusCode.NotImplemented, method + " Method Not Implemented");
                            }
                            HTTPMethod httpMethod = _supportedMethods[method];

                            url = HttpUtility.UrlDecode(url);

                            //Build the request object
                            request = new HTTPRequest(httpMethod, url);

                            //Add all headers to the request object
                            FillHeaders(request, reader);

                            //Handle encoding for this request
                            Encoding clientEncoding = InferEncoding(request);

                            //Extract all the data from the URL (base and query)
                            ExtractQuery(request, clientEncoding);

                            //Extract and decode all the POST data
                            ExtractPOST(request, reader, clientEncoding);

                            bool keepAlive = false;
                            // According to spec, Keep-Alive is ON by default
                            if (version == "HTTP/1.1")
                            {
                                keepAlive = true;
                            }
                            if (request.Headers.ContainsKey(HTTPHeader.Connection))
                            {
                                if (request.Headers[HTTPHeader.Connection].ToLower().Equals("close"))
                                {
                                    keepAlive = false;
                                    response.SetHeader(HTTPHeader.Connection, "close");
                                }
                            }

                            //Keep-Alive can only work on a multithreaded server!
                            if (!keepAlive || !MultiThreaded)
                            {
                                leaveOpen = false;
                                response.SetHeader(HTTPHeader.Connection, "close");
                            }
                            //Pass this on to the route solver
                            OnLog(request, null);
                            Routes.HandleRequest(request, response, stream);
                            OnLog(request, response);
                        }
                    }
                    catch (HandlingException e)
                    {
                        if (response != null)
                        {
                            try
                            {
                                // try to return the response
                                response.WriteError(e.Status, e.ErrorMessage);
                                response.Respond(stream);
                            }
                            catch
                            {
                                // ignore silently if it is not posible
                            }
                            OnLog(request, response);
                        }
                    }
                    catch (ThreadAbortException)
                    {
                        // Do nothing, server is terminating
                    }
                    catch (Exception e)
                    {
                        if (response != null)
                        {
                            try
                            {
                                // try to return the response
                                response.WriteError(HTTPStatusCode.InternalServerError, "Internal Server Error. " + e.Message);
                                response.Respond(stream);
                            }
                            catch
                            {
                                // ignore silently if it is not posible
                            }
                            OnLog(request, response);
                        }
                    }
                    finally
                    {
                        reader.Close();
                    }
                }
                finally
                {
                    stream.Dispose();
                }
            }
            finally
            {
                lock (_openTcpClients)
                    _openTcpClients.Remove(client);
            }
        }
Beispiel #18
0
 public bool Process(HTTPRequest request, HTTPResponse response)
 {
     // Make IE stop cacheing AJAX requests
     response.SetHeader("Cache-Control", "no-cache, no-store");
     return(true);
 }