summaryrefslogtreecommitdiffstats
path: root/pki/base/util/src/com/netscape/cmsutil/http
diff options
context:
space:
mode:
Diffstat (limited to 'pki/base/util/src/com/netscape/cmsutil/http')
-rw-r--r--pki/base/util/src/com/netscape/cmsutil/http/ConnectAsync.java7
-rw-r--r--pki/base/util/src/com/netscape/cmsutil/http/Http.java1
-rw-r--r--pki/base/util/src/com/netscape/cmsutil/http/HttpClient.java61
-rw-r--r--pki/base/util/src/com/netscape/cmsutil/http/HttpEofException.java2
-rw-r--r--pki/base/util/src/com/netscape/cmsutil/http/HttpMessage.java44
-rw-r--r--pki/base/util/src/com/netscape/cmsutil/http/HttpProtocolException.java2
-rw-r--r--pki/base/util/src/com/netscape/cmsutil/http/HttpRequest.java31
-rw-r--r--pki/base/util/src/com/netscape/cmsutil/http/HttpResponse.java18
-rw-r--r--pki/base/util/src/com/netscape/cmsutil/http/JssSSLSocketFactory.java61
9 files changed, 133 insertions, 94 deletions
diff --git a/pki/base/util/src/com/netscape/cmsutil/http/ConnectAsync.java b/pki/base/util/src/com/netscape/cmsutil/http/ConnectAsync.java
index ca230ca21..8922f38dd 100644
--- a/pki/base/util/src/com/netscape/cmsutil/http/ConnectAsync.java
+++ b/pki/base/util/src/com/netscape/cmsutil/http/ConnectAsync.java
@@ -17,10 +17,12 @@
// --- END COPYRIGHT BLOCK ---
package com.netscape.cmsutil.http;
+
import java.net.SocketException;
import com.netscape.cmsutil.net.ISocketFactory;
+
public class ConnectAsync extends Thread {
String host = null;
int port = 0;
@@ -31,9 +33,9 @@ public class ConnectAsync extends Thread {
this.host = host;
this.port = port;
this.obj = sock;
- setName("ConnectAsync");
+ setName("ConnectAsync");
}
-
+
public void run() {
try {
obj.makeSocket(host, port);
@@ -44,3 +46,4 @@ public class ConnectAsync extends Thread {
}
}
}
+
diff --git a/pki/base/util/src/com/netscape/cmsutil/http/Http.java b/pki/base/util/src/com/netscape/cmsutil/http/Http.java
index 2cda7fd12..acece15d1 100644
--- a/pki/base/util/src/com/netscape/cmsutil/http/Http.java
+++ b/pki/base/util/src/com/netscape/cmsutil/http/Http.java
@@ -17,6 +17,7 @@
// --- END COPYRIGHT BLOCK ---
package com.netscape.cmsutil.http;
+
public class Http {
public static final String HttpVers = "HTTP/1.0";
diff --git a/pki/base/util/src/com/netscape/cmsutil/http/HttpClient.java b/pki/base/util/src/com/netscape/cmsutil/http/HttpClient.java
index 2c0134687..130d747d6 100644
--- a/pki/base/util/src/com/netscape/cmsutil/http/HttpClient.java
+++ b/pki/base/util/src/com/netscape/cmsutil/http/HttpClient.java
@@ -30,8 +30,9 @@ import org.mozilla.jss.ssl.SSLCertificateApprovalCallback;
import com.netscape.cmsutil.net.ISocketFactory;
/**
- * basic http client. not optimized for performance. handles only string
- * content.
+ * basic http client.
+ * not optimized for performance.
+ * handles only string content.
*/
public class HttpClient {
protected ISocketFactory mFactory = null;
@@ -53,19 +54,18 @@ public class HttpClient {
mFactory = factory;
}
- public HttpClient(ISocketFactory factory,
- SSLCertificateApprovalCallback certApprovalCallback) {
+ public HttpClient(ISocketFactory factory, SSLCertificateApprovalCallback certApprovalCallback) {
mFactory = factory;
mCertApprovalCallback = certApprovalCallback;
}
- public void connect(String host, int port) throws IOException {
+ public void connect(String host, int port)
+ throws IOException {
if (mFactory != null) {
if (mCertApprovalCallback == null) {
mSocket = mFactory.makeSocket(host, port);
} else {
- mSocket = mFactory.makeSocket(host, port,
- mCertApprovalCallback, null);
+ mSocket = mFactory.makeSocket(host, port, mCertApprovalCallback, null);
}
} else {
mSocket = new Socket(host, port);
@@ -76,7 +76,7 @@ public class HttpClient {
throw e;
}
-
+
mInputStream = mSocket.getInputStream();
mOutputStream = mSocket.getOutputStream();
mInputStreamReader = new InputStreamReader(mInputStream, "UTF8");
@@ -86,7 +86,8 @@ public class HttpClient {
}
// Inserted by beomsuk
- public void connect(String host, int port, int timeout) throws IOException {
+ public void connect(String host, int port, int timeout)
+ throws IOException {
if (mFactory != null) {
mSocket = mFactory.makeSocket(host, port, timeout);
} else {
@@ -98,7 +99,7 @@ public class HttpClient {
throw e;
}
-
+
mInputStream = mSocket.getInputStream();
mOutputStream = mSocket.getOutputStream();
mInputStreamReader = new InputStreamReader(mInputStream, "UTF8");
@@ -113,11 +114,14 @@ public class HttpClient {
}
/**
- * Sends a request to http server. Returns a http response.
+ * Sends a request to http server.
+ * Returns a http response.
*/
- public HttpResponse send(HttpRequest request) throws IOException {
+ public HttpResponse send(HttpRequest request)
+ throws IOException {
HttpResponse resp = new HttpResponse();
+
if (mOutputStream == null)
throw new IOException("Output stream not initialized");
request.write(mOutputStreamWriter);
@@ -132,7 +136,8 @@ public class HttpClient {
return resp;
}
- public void disconnect() throws IOException {
+ public void disconnect()
+ throws IOException {
mSocket.close();
mInputStream = null;
mOutputStream = null;
@@ -166,7 +171,8 @@ public class HttpClient {
/**
* unit test
*/
- public static void main(String args[]) throws Exception {
+ public static void main(String args[])
+ throws Exception {
HttpClient c = new HttpClient();
HttpRequest req = new HttpRequest();
HttpResponse resp = null;
@@ -176,7 +182,7 @@ public class HttpClient {
req.setMethod("GET");
req.setURI(args[2]);
- if (args.length >= 4)
+ if (args.length >= 4)
req.setHeader("Connection", args[3]);
resp = c.send(req);
@@ -185,30 +191,29 @@ public class HttpClient {
System.out.println("reason " + resp.getReasonPhrase());
System.out.println("content " + resp.getContent());
- // String lenstr = resp.getHeader("Content-Length");
- // System.out.println("content len is "+lenstr);
- // int length = Integer.parseInt(lenstr);
- // char[] content = new char[length];
- // c.mBufferedReader.read(content, 0, content.length);
- // System.out.println(content);
+ //String lenstr = resp.getHeader("Content-Length");
+ //System.out.println("content len is "+lenstr);
+ //int length = Integer.parseInt(lenstr);
+ //char[] content = new char[length];
+ //c.mBufferedReader.read(content, 0, content.length);
+ //System.out.println(content);
if (args.length >= 4 && args[3].equalsIgnoreCase("keep-alive")) {
int len;
char[] msgbody;
for (int i = 0; i < 2; i++) {
- if (i == 1)
- req.setHeader("Connection", "Close");
+ if (i == 1) req.setHeader("Connection", "Close");
resp = c.send(req);
System.out.println("version " + resp.getHttpVers());
System.out.println("status code " + resp.getStatusCode());
System.out.println("reason " + resp.getReasonPhrase());
System.out.println("content " + resp.getContent());
- // len = Integer.parseInt(resp.getHeader("Content-Length"));
- // System.out.println("content len is "+len);
- // msgbody = new char[len];
- // c.mBufferedReader.read(msgbody, 0, len);
- // System.out.println(content);
+ //len = Integer.parseInt(resp.getHeader("Content-Length"));
+ //System.out.println("content len is "+len);
+ //msgbody = new char[len];
+ //c.mBufferedReader.read(msgbody, 0, len);
+ //System.out.println(content);
}
}
}
diff --git a/pki/base/util/src/com/netscape/cmsutil/http/HttpEofException.java b/pki/base/util/src/com/netscape/cmsutil/http/HttpEofException.java
index 824b9ea2a..e5573612e 100644
--- a/pki/base/util/src/com/netscape/cmsutil/http/HttpEofException.java
+++ b/pki/base/util/src/com/netscape/cmsutil/http/HttpEofException.java
@@ -17,8 +17,10 @@
// --- END COPYRIGHT BLOCK ---
package com.netscape.cmsutil.http;
+
import java.io.IOException;
+
public class HttpEofException extends IOException {
/**
*
diff --git a/pki/base/util/src/com/netscape/cmsutil/http/HttpMessage.java b/pki/base/util/src/com/netscape/cmsutil/http/HttpMessage.java
index b0a0f0df7..93eeef68c 100644
--- a/pki/base/util/src/com/netscape/cmsutil/http/HttpMessage.java
+++ b/pki/base/util/src/com/netscape/cmsutil/http/HttpMessage.java
@@ -17,18 +17,21 @@
// --- END COPYRIGHT BLOCK ---
package com.netscape.cmsutil.http;
+
import java.io.BufferedReader;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.util.Enumeration;
import java.util.Hashtable;
+
/**
- * Basic HTTP Message, excluding message body. Not optimized for performance.
+ * Basic HTTP Message, excluding message body.
+ * Not optimized for performance.
* Set fields or parse from input.
*/
public class HttpMessage {
- protected String mLine = null; // request or response line.
+ protected String mLine = null; // request or response line.
protected Hashtable mHeaders = null;
protected String mContent = null; // arbitrary content chars assumed.
@@ -39,14 +42,14 @@ public class HttpMessage {
mHeaders = new Hashtable();
}
- /**
+ /**
* Set a header field. <br>
* Content-length is automatically set on write.<br>
- * If value spans multiple lines must be in proper http format for multiple
- * lines.
+ * If value spans multiple lines must be in proper http format for
+ * multiple lines.
*/
public void setHeader(String name, String value) {
- if (mHeaders == null)
+ if (mHeaders == null)
mHeaders = new Hashtable();
mHeaders.put(name.toLowerCase(), value);
}
@@ -59,9 +62,11 @@ public class HttpMessage {
}
/**
- * write http headers does not support values of more than one line
+ * write http headers
+ * does not support values of more than one line
*/
- public void writeHeaders(OutputStreamWriter writer) throws IOException {
+ public void writeHeaders(OutputStreamWriter writer)
+ throws IOException {
if (mHeaders != null) {
Enumeration keys = mHeaders.keys();
String header, value;
@@ -76,10 +81,11 @@ public class HttpMessage {
}
/**
- * read http headers. does not support values of more than one line or
- * multivalue headers.
+ * read http headers.
+ * does not support values of more than one line or multivalue headers.
*/
- public void readHeaders(BufferedReader reader) throws IOException {
+ public void readHeaders(BufferedReader reader)
+ throws IOException {
mHeaders = new Hashtable();
int colon;
@@ -87,7 +93,7 @@ public class HttpMessage {
while (true) {
line = reader.readLine();
- if (line == null || line.equals(""))
+ if (line == null || line.equals(""))
break;
colon = line.indexOf(':');
if (colon == -1) {
@@ -100,7 +106,8 @@ public class HttpMessage {
}
}
- public void write(OutputStreamWriter writer) throws IOException {
+ public void write(OutputStreamWriter writer)
+ throws IOException {
writer.write(mLine + Http.CRLF);
writeHeaders(writer);
writer.flush();
@@ -110,12 +117,13 @@ public class HttpMessage {
writer.flush();
}
- public void parse(BufferedReader reader) throws IOException {
+ public void parse(BufferedReader reader)
+ throws IOException {
String line = reader.readLine();
- // if (line == null) {
- // throw new HttpEofException("End of stream reached");
- // }
+// if (line == null) {
+ // throw new HttpEofException("End of stream reached");
+ // }
if (line.equals("")) {
throw new HttpProtocolException("Bad Http req/resp line " + line);
}
@@ -135,7 +143,7 @@ public class HttpMessage {
done = reader.read(cbuf, total, len - total);
total += done;
}
-
+
mContent = new String(cbuf);
}
}
diff --git a/pki/base/util/src/com/netscape/cmsutil/http/HttpProtocolException.java b/pki/base/util/src/com/netscape/cmsutil/http/HttpProtocolException.java
index b5ceb1d7f..6b2fc75fe 100644
--- a/pki/base/util/src/com/netscape/cmsutil/http/HttpProtocolException.java
+++ b/pki/base/util/src/com/netscape/cmsutil/http/HttpProtocolException.java
@@ -17,8 +17,10 @@
// --- END COPYRIGHT BLOCK ---
package com.netscape.cmsutil.http;
+
import java.io.IOException;
+
public class HttpProtocolException extends IOException {
/**
*
diff --git a/pki/base/util/src/com/netscape/cmsutil/http/HttpRequest.java b/pki/base/util/src/com/netscape/cmsutil/http/HttpRequest.java
index 0c3333afb..76232a2dc 100644
--- a/pki/base/util/src/com/netscape/cmsutil/http/HttpRequest.java
+++ b/pki/base/util/src/com/netscape/cmsutil/http/HttpRequest.java
@@ -17,13 +17,16 @@
// --- END COPYRIGHT BLOCK ---
package com.netscape.cmsutil.http;
+
import java.io.BufferedReader;
import java.io.IOException;
import java.io.OutputStreamWriter;
+
/**
- * Basic HTTP Request. not optimized for performance. Set fields or parse from
- * input. Handles text content.
+ * Basic HTTP Request. not optimized for performance.
+ * Set fields or parse from input.
+ * Handles text content.
*/
public class HttpRequest extends HttpMessage {
public static final String GET = "GET";
@@ -44,8 +47,10 @@ public class HttpRequest extends HttpMessage {
/**
* set set request method.
*/
- public void setMethod(String method) throws HttpProtocolException {
- if (!method.equals(GET) && !method.equals(HEAD) && !method.equals(POST))
+ public void setMethod(String method)
+ throws HttpProtocolException {
+ if (!method.equals(GET) && !method.equals(HEAD) &&
+ !method.equals(POST))
throw new HttpProtocolException("No such method " + method);
mMethod = method;
}
@@ -60,12 +65,13 @@ public class HttpRequest extends HttpMessage {
/**
* write request to the http client
*/
- public void write(OutputStreamWriter writer) throws IOException {
+ public void write(OutputStreamWriter writer)
+ throws IOException {
if (mMethod == null || mURI == null) {
HttpProtocolException e = new HttpProtocolException(
"Http request method or uri not initialized");
- // e.printStackTrace();
+ //e.printStackTrace();
throw e;
}
@@ -76,17 +82,18 @@ public class HttpRequest extends HttpMessage {
/**
* parse a http request from a http client
*/
- public void parse(BufferedReader reader) throws IOException {
+ public void parse(BufferedReader reader)
+ throws IOException {
super.parse(reader);
int method = mLine.indexOf(Http.SP);
mMethod = mLine.substring(0, method);
- if (!mMethod.equals(GET) && !mMethod.equals(POST)
- && !mMethod.equals(HEAD)) {
+ if (!mMethod.equals(GET) && !mMethod.equals(POST) &&
+ !mMethod.equals(HEAD)) {
reset();
throw new HttpProtocolException("Bad Http request method");
- }
+ }
int uri = mLine.lastIndexOf(Http.SP);
@@ -94,8 +101,8 @@ public class HttpRequest extends HttpMessage {
mHttpVers = mLine.substring(uri + 1);
if (!mHttpVers.equals("")) {
- if (!mHttpVers.equals(Http.Vers1_0)
- && !mHttpVers.equals(Http.Vers1_1)) {
+ if (!mHttpVers.equals(Http.Vers1_0) &&
+ !mHttpVers.equals(Http.Vers1_1)) {
reset();
throw new HttpProtocolException("Bad Http version in request");
}
diff --git a/pki/base/util/src/com/netscape/cmsutil/http/HttpResponse.java b/pki/base/util/src/com/netscape/cmsutil/http/HttpResponse.java
index bf425ddf8..09d8e562d 100644
--- a/pki/base/util/src/com/netscape/cmsutil/http/HttpResponse.java
+++ b/pki/base/util/src/com/netscape/cmsutil/http/HttpResponse.java
@@ -17,13 +17,16 @@
// --- END COPYRIGHT BLOCK ---
package com.netscape.cmsutil.http;
+
import java.io.BufferedReader;
import java.io.IOException;
import java.io.OutputStreamWriter;
+
/**
- * Basic HTTP Response. Set fields or parse from input. Handles only text
- * content.
+ * Basic HTTP Response.
+ * Set fields or parse from input.
+ * Handles only text content.
*/
public class HttpResponse extends HttpMessage {
protected String mStatusCode = null;
@@ -68,11 +71,12 @@ public class HttpResponse extends HttpMessage {
/**
* write the response out to the http client
*/
- public void write(OutputStreamWriter writer) throws IOException {
+ public void write(OutputStreamWriter writer)
+ throws IOException {
if (mStatusCode == null) {
throw new HttpProtocolException("status code not set in response");
}
- // write status-line
+ // write status-line
mLine = Http.HttpVers + " " + mStatusCode + " ";
if (mReasonPhrase != null)
mLine += mReasonPhrase;
@@ -83,7 +87,8 @@ public class HttpResponse extends HttpMessage {
/**
* parse a http response from a http server
*/
- public void parse(BufferedReader reader) throws IOException {
+ public void parse(BufferedReader reader)
+ throws IOException {
mHttpVers = null;
mStatusCode = null;
mReasonPhrase = null;
@@ -97,7 +102,8 @@ public class HttpResponse extends HttpMessage {
throw new HttpProtocolException("no Http version in response");
}
mHttpVers = mLine.substring(0, httpvers);
- if (!mHttpVers.equals(Http.Vers1_0) && !mHttpVers.equals(Http.Vers1_1)) {
+ if (!mHttpVers.equals(Http.Vers1_0) &&
+ !mHttpVers.equals(Http.Vers1_1)) {
reset();
throw new HttpProtocolException("Bad Http version in response");
}
diff --git a/pki/base/util/src/com/netscape/cmsutil/http/JssSSLSocketFactory.java b/pki/base/util/src/com/netscape/cmsutil/http/JssSSLSocketFactory.java
index 45dc9d288..501886b54 100644
--- a/pki/base/util/src/com/netscape/cmsutil/http/JssSSLSocketFactory.java
+++ b/pki/base/util/src/com/netscape/cmsutil/http/JssSSLSocketFactory.java
@@ -17,6 +17,7 @@
// --- END COPYRIGHT BLOCK ---
package com.netscape.cmsutil.http;
+
import java.io.IOException;
import java.net.Socket;
import java.net.SocketException;
@@ -34,12 +35,12 @@ import com.netscape.cmsutil.net.ISocketFactory;
/**
* Uses NSS ssl socket.
- *
+ *
* @version $Revision$ $Date$
*/
public class JssSSLSocketFactory implements ISocketFactory {
private String mClientAuthCertNickname = null;
- private SSLSocket s = null;
+ private SSLSocket s = null;
public JssSSLSocketFactory() {
}
@@ -61,62 +62,66 @@ public class JssSSLSocketFactory implements ISocketFactory {
SSLSocket.TLS_RSA_WITH_AES_256_CBC_SHA,
SSLSocket.TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA,
SSLSocket.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
- // SSLSocket.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
- // SSLSocket.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
- // SSLSocket.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
+ //SSLSocket.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
+ //SSLSocket.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
+ //SSLSocket.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
SSLSocket.TLS_DHE_DSS_WITH_AES_128_CBC_SHA,
SSLSocket.TLS_DHE_DSS_WITH_AES_256_CBC_SHA,
SSLSocket.TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
- SSLSocket.TLS_DHE_RSA_WITH_AES_256_CBC_SHA, 0 };
-
+ SSLSocket.TLS_DHE_RSA_WITH_AES_256_CBC_SHA,
+ 0
+ };
+
static {
int i;
- for (i = SSLSocket.SSL2_RC4_128_WITH_MD5; i <= SSLSocket.SSL2_RC2_128_CBC_EXPORT40_WITH_MD5; ++i) {
+ for (i = SSLSocket.SSL2_RC4_128_WITH_MD5;
+ i <= SSLSocket.SSL2_RC2_128_CBC_EXPORT40_WITH_MD5; ++i) {
try {
SSLSocket.setCipherPreferenceDefault(i, false);
- } catch (SocketException e) {
+ } catch( SocketException e) {
}
}
- // skip SSL_EN_IDEA_128_EDE3_CBC_WITH_MD5
- for (i = SSLSocket.SSL2_DES_64_CBC_WITH_MD5; i <= SSLSocket.SSL2_DES_192_EDE3_CBC_WITH_MD5; ++i) {
+ //skip SSL_EN_IDEA_128_EDE3_CBC_WITH_MD5
+ for (i = SSLSocket.SSL2_DES_64_CBC_WITH_MD5;
+ i <= SSLSocket.SSL2_DES_192_EDE3_CBC_WITH_MD5; ++i) {
try {
SSLSocket.setCipherPreferenceDefault(i, false);
- } catch (SocketException e) {
+ } catch( SocketException e) {
}
}
for (i = 0; cipherSuites[i] != 0; ++i) {
try {
SSLSocket.setCipherPreferenceDefault(cipherSuites[i], true);
- } catch (SocketException e) {
+ } catch( SocketException e) {
}
}
}
- public Socket makeSocket(String host, int port) throws IOException,
- UnknownHostException {
+ public Socket makeSocket(String host, int port)
+ throws IOException, UnknownHostException {
return makeSocket(host, port, null, null);
}
- public Socket makeSocket(String host, int port,
- SSLCertificateApprovalCallback certApprovalCallback,
- SSLClientCertificateSelectionCallback clientCertCallback)
- throws IOException, UnknownHostException {
+ public Socket makeSocket(String host, int port,
+ SSLCertificateApprovalCallback certApprovalCallback,
+ SSLClientCertificateSelectionCallback clientCertCallback)
+ throws IOException, UnknownHostException {
try {
s = new SSLSocket(host, port, null, 0, certApprovalCallback,
- clientCertCallback);
+ clientCertCallback);
for (int i = 0; cipherSuites[i] != 0; ++i) {
try {
SSLSocket.setCipherPreferenceDefault(cipherSuites[i], true);
- } catch (SocketException e) {
+ } catch( SocketException e) {
}
}
s.setUseClientMode(true);
s.enableSSL2(false);
- // TODO Do we rally want to set the default each time?
+ //TODO Do we rally want to set the default each time?
SSLSocket.enableSSL2Default(false);
s.enableV2CompatibleHello(false);
@@ -130,8 +135,7 @@ public class JssSSLSocketFactory implements ISocketFactory {
// report error if the nickName is invalid.
// So we check this ourself using
// findCertByNickname
- X509Certificate cert = CryptoManager.getInstance()
- .findCertByNickname(mClientAuthCertNickname);
+ X509Certificate cert = CryptoManager.getInstance().findCertByNickname(mClientAuthCertNickname);
s.setClientCertNickname(mClientAuthCertNickname);
}
@@ -150,8 +154,8 @@ public class JssSSLSocketFactory implements ISocketFactory {
return s;
}
- public Socket makeSocket(String host, int port, int timeout)
- throws IOException, UnknownHostException {
+ public Socket makeSocket(String host, int port, int timeout)
+ throws IOException, UnknownHostException {
Thread t = new ConnectAsync(this, host, port);
t.start();
@@ -159,7 +163,7 @@ public class JssSSLSocketFactory implements ISocketFactory {
t.join(1000 * timeout);
} catch (InterruptedException e) {
}
-
+
if (t.isAlive()) {
}
@@ -175,8 +179,9 @@ public class JssSSLSocketFactory implements ISocketFactory {
public ClientHandshakeCB(Object sc) {
this.sc = sc;
}
-
+
public void handshakeCompleted(SSLHandshakeCompletedEvent event) {
}
}
}
+