handle body json and content type of HttpServletRequest
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty height:90px;width:728px;box-sizing:border-box;
I am working on a http Gateway code to make a patch.
The problem: an application send http request with content type "application/json" but their body has a multiple json. My work is to filter and rewrite this type of http request by:
- Extract the Json body
- Rewrite the Json body to be in NEWLINE Delimited Format (NDJSON)
- Change the content type to "application/x-ndjson"
I tried to change only the content-typebut doesn't solve the problem, because the body was received in bad format.
bad body received with simple json: "content-type"="application/json",
json body 1 json body 2 json body 3
correct body with multiple json: content-type="application/x-ndjson", should be in this format
json body 1 NEWLINE
json body 2 NEWLINE
json body 3 NEWLINE
NEWLINE
Here's my Code:
import com.google.common.collect.Lists;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Enumeration;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.hadoop.gateway.SpiGatewayMessages;
import org.apache.hadoop.gateway.SpiGatewayResources;
import org.apache.hadoop.gateway.audit.api.Auditor;
import org.apache.hadoop.gateway.dispatch.DefaultDispatch;
import org.apache.hadoop.gateway.i18n.messages.MessagesFactory;
import org.apache.hadoop.gateway.i18n.resources.ResourcesFactory;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.StatusLine;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.InputStreamEntity;
import org.apache.http.client.methods.RequestBuilder;
public class ElasticsearchDispatch
extends DefaultDispatch
protected static SpiGatewayMessages LOG = (SpiGatewayMessages)MessagesFactory.get(SpiGatewayMessages.class);
protected static SpiGatewayResources RES = (SpiGatewayResources)ResourcesFactory.get(SpiGatewayResources.class);
public ElasticsearchDispatch()
protected void executeRequest(HttpUriRequest outboundRequest, HttpServletRequest inboundRequest, HttpServletResponse outboundResponse)
throws IOException
List<String> excludeHeaders = Lists.newArrayList(new String "Content-Length" );
Enumeration<String> headersName = inboundRequest.getHeaderNames();
while (headersName.hasMoreElements())
String headerName = (String)headersName.nextElement();
if ((outboundRequest.getHeaders(headerName).length == 0) && (!excludeHeaders.contains(headerName)))
outboundRequest.addHeader(headerName, inboundRequest.getHeader(headerName));
HttpResponse inboundResponse = executeOutboundRequest(outboundRequest);
writeOutboundResponse(outboundRequest, inboundRequest, outboundResponse, inboundResponse);
private HttpUriRequest removeParameter(HttpUriRequest request, String param) throws URISyntaxException
URI uri = request.getURI();
URIBuilder builder = new URIBuilder(uri);
List<NameValuePair> nameValuePairs = builder.getQueryParams();
if ((nameValuePairs != null) && (!nameValuePairs.isEmpty()))
builder.clearParameters();
for (NameValuePair nvp : nameValuePairs)
if (!param.equals(nvp.getName()))
builder.setParameter(nvp.getName(), nvp.getValue());
((HttpRequestBase)request).setURI(builder.build());
return request;
protected HttpResponse executeOutboundRequest(HttpUriRequest outboundRequest) throws IOException
LOG.dispatchRequest(outboundRequest.getMethod(), outboundRequest.getURI());
HttpResponse inboundResponse = null;
try
inboundResponse = client.execute(removeParameter(outboundRequest, "doAs"));
catch (IOException e)
LOG.dispatchServiceConnectionException(outboundRequest.getURI(), e);
auditor.audit("dispatch", outboundRequest.getURI().toString(), "uri", "failure");
throw new IOException(RES.dispatchConnectionError());
catch (URISyntaxException e)
e.printStackTrace();
finally
if (inboundResponse != null)
int statusCode = inboundResponse.getStatusLine().getStatusCode();
if (statusCode != 201)
LOG.dispatchResponseStatusCode(statusCode);
else
Header location = inboundResponse.getFirstHeader("Location");
if (location == null)
LOG.dispatchResponseStatusCode(statusCode);
else
LOG.dispatchResponseCreatedStatusCode(statusCode, location.getValue());
auditor.audit("dispatch", outboundRequest.getURI().toString(), "uri", "success", RES.responseStatus(statusCode));
else
auditor.audit("dispatch", outboundRequest.getURI().toString(), "uri", "unavailable");
return inboundResponse;
protected HttpEntity createRequestEntity(HttpServletRequest request)
throws IOException
String contentType = request.getContentType();
int contentLength = request.getContentLength();
InputStream contentStream = request.getInputStream();
HttpEntity entity;
if (contentType == null)
entity = new InputStreamEntity(contentStream, contentLength);
else
entity = new InputStreamEntity(contentStream, contentLength, ContentType.parse(contentType));
return entity;
java json ndjson
add a comment |
I am working on a http Gateway code to make a patch.
The problem: an application send http request with content type "application/json" but their body has a multiple json. My work is to filter and rewrite this type of http request by:
- Extract the Json body
- Rewrite the Json body to be in NEWLINE Delimited Format (NDJSON)
- Change the content type to "application/x-ndjson"
I tried to change only the content-typebut doesn't solve the problem, because the body was received in bad format.
bad body received with simple json: "content-type"="application/json",
json body 1 json body 2 json body 3
correct body with multiple json: content-type="application/x-ndjson", should be in this format
json body 1 NEWLINE
json body 2 NEWLINE
json body 3 NEWLINE
NEWLINE
Here's my Code:
import com.google.common.collect.Lists;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Enumeration;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.hadoop.gateway.SpiGatewayMessages;
import org.apache.hadoop.gateway.SpiGatewayResources;
import org.apache.hadoop.gateway.audit.api.Auditor;
import org.apache.hadoop.gateway.dispatch.DefaultDispatch;
import org.apache.hadoop.gateway.i18n.messages.MessagesFactory;
import org.apache.hadoop.gateway.i18n.resources.ResourcesFactory;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.StatusLine;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.InputStreamEntity;
import org.apache.http.client.methods.RequestBuilder;
public class ElasticsearchDispatch
extends DefaultDispatch
protected static SpiGatewayMessages LOG = (SpiGatewayMessages)MessagesFactory.get(SpiGatewayMessages.class);
protected static SpiGatewayResources RES = (SpiGatewayResources)ResourcesFactory.get(SpiGatewayResources.class);
public ElasticsearchDispatch()
protected void executeRequest(HttpUriRequest outboundRequest, HttpServletRequest inboundRequest, HttpServletResponse outboundResponse)
throws IOException
List<String> excludeHeaders = Lists.newArrayList(new String "Content-Length" );
Enumeration<String> headersName = inboundRequest.getHeaderNames();
while (headersName.hasMoreElements())
String headerName = (String)headersName.nextElement();
if ((outboundRequest.getHeaders(headerName).length == 0) && (!excludeHeaders.contains(headerName)))
outboundRequest.addHeader(headerName, inboundRequest.getHeader(headerName));
HttpResponse inboundResponse = executeOutboundRequest(outboundRequest);
writeOutboundResponse(outboundRequest, inboundRequest, outboundResponse, inboundResponse);
private HttpUriRequest removeParameter(HttpUriRequest request, String param) throws URISyntaxException
URI uri = request.getURI();
URIBuilder builder = new URIBuilder(uri);
List<NameValuePair> nameValuePairs = builder.getQueryParams();
if ((nameValuePairs != null) && (!nameValuePairs.isEmpty()))
builder.clearParameters();
for (NameValuePair nvp : nameValuePairs)
if (!param.equals(nvp.getName()))
builder.setParameter(nvp.getName(), nvp.getValue());
((HttpRequestBase)request).setURI(builder.build());
return request;
protected HttpResponse executeOutboundRequest(HttpUriRequest outboundRequest) throws IOException
LOG.dispatchRequest(outboundRequest.getMethod(), outboundRequest.getURI());
HttpResponse inboundResponse = null;
try
inboundResponse = client.execute(removeParameter(outboundRequest, "doAs"));
catch (IOException e)
LOG.dispatchServiceConnectionException(outboundRequest.getURI(), e);
auditor.audit("dispatch", outboundRequest.getURI().toString(), "uri", "failure");
throw new IOException(RES.dispatchConnectionError());
catch (URISyntaxException e)
e.printStackTrace();
finally
if (inboundResponse != null)
int statusCode = inboundResponse.getStatusLine().getStatusCode();
if (statusCode != 201)
LOG.dispatchResponseStatusCode(statusCode);
else
Header location = inboundResponse.getFirstHeader("Location");
if (location == null)
LOG.dispatchResponseStatusCode(statusCode);
else
LOG.dispatchResponseCreatedStatusCode(statusCode, location.getValue());
auditor.audit("dispatch", outboundRequest.getURI().toString(), "uri", "success", RES.responseStatus(statusCode));
else
auditor.audit("dispatch", outboundRequest.getURI().toString(), "uri", "unavailable");
return inboundResponse;
protected HttpEntity createRequestEntity(HttpServletRequest request)
throws IOException
String contentType = request.getContentType();
int contentLength = request.getContentLength();
InputStream contentStream = request.getInputStream();
HttpEntity entity;
if (contentType == null)
entity = new InputStreamEntity(contentStream, contentLength);
else
entity = new InputStreamEntity(contentStream, contentLength, ContentType.parse(contentType));
return entity;
java json ndjson
add a comment |
I am working on a http Gateway code to make a patch.
The problem: an application send http request with content type "application/json" but their body has a multiple json. My work is to filter and rewrite this type of http request by:
- Extract the Json body
- Rewrite the Json body to be in NEWLINE Delimited Format (NDJSON)
- Change the content type to "application/x-ndjson"
I tried to change only the content-typebut doesn't solve the problem, because the body was received in bad format.
bad body received with simple json: "content-type"="application/json",
json body 1 json body 2 json body 3
correct body with multiple json: content-type="application/x-ndjson", should be in this format
json body 1 NEWLINE
json body 2 NEWLINE
json body 3 NEWLINE
NEWLINE
Here's my Code:
import com.google.common.collect.Lists;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Enumeration;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.hadoop.gateway.SpiGatewayMessages;
import org.apache.hadoop.gateway.SpiGatewayResources;
import org.apache.hadoop.gateway.audit.api.Auditor;
import org.apache.hadoop.gateway.dispatch.DefaultDispatch;
import org.apache.hadoop.gateway.i18n.messages.MessagesFactory;
import org.apache.hadoop.gateway.i18n.resources.ResourcesFactory;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.StatusLine;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.InputStreamEntity;
import org.apache.http.client.methods.RequestBuilder;
public class ElasticsearchDispatch
extends DefaultDispatch
protected static SpiGatewayMessages LOG = (SpiGatewayMessages)MessagesFactory.get(SpiGatewayMessages.class);
protected static SpiGatewayResources RES = (SpiGatewayResources)ResourcesFactory.get(SpiGatewayResources.class);
public ElasticsearchDispatch()
protected void executeRequest(HttpUriRequest outboundRequest, HttpServletRequest inboundRequest, HttpServletResponse outboundResponse)
throws IOException
List<String> excludeHeaders = Lists.newArrayList(new String "Content-Length" );
Enumeration<String> headersName = inboundRequest.getHeaderNames();
while (headersName.hasMoreElements())
String headerName = (String)headersName.nextElement();
if ((outboundRequest.getHeaders(headerName).length == 0) && (!excludeHeaders.contains(headerName)))
outboundRequest.addHeader(headerName, inboundRequest.getHeader(headerName));
HttpResponse inboundResponse = executeOutboundRequest(outboundRequest);
writeOutboundResponse(outboundRequest, inboundRequest, outboundResponse, inboundResponse);
private HttpUriRequest removeParameter(HttpUriRequest request, String param) throws URISyntaxException
URI uri = request.getURI();
URIBuilder builder = new URIBuilder(uri);
List<NameValuePair> nameValuePairs = builder.getQueryParams();
if ((nameValuePairs != null) && (!nameValuePairs.isEmpty()))
builder.clearParameters();
for (NameValuePair nvp : nameValuePairs)
if (!param.equals(nvp.getName()))
builder.setParameter(nvp.getName(), nvp.getValue());
((HttpRequestBase)request).setURI(builder.build());
return request;
protected HttpResponse executeOutboundRequest(HttpUriRequest outboundRequest) throws IOException
LOG.dispatchRequest(outboundRequest.getMethod(), outboundRequest.getURI());
HttpResponse inboundResponse = null;
try
inboundResponse = client.execute(removeParameter(outboundRequest, "doAs"));
catch (IOException e)
LOG.dispatchServiceConnectionException(outboundRequest.getURI(), e);
auditor.audit("dispatch", outboundRequest.getURI().toString(), "uri", "failure");
throw new IOException(RES.dispatchConnectionError());
catch (URISyntaxException e)
e.printStackTrace();
finally
if (inboundResponse != null)
int statusCode = inboundResponse.getStatusLine().getStatusCode();
if (statusCode != 201)
LOG.dispatchResponseStatusCode(statusCode);
else
Header location = inboundResponse.getFirstHeader("Location");
if (location == null)
LOG.dispatchResponseStatusCode(statusCode);
else
LOG.dispatchResponseCreatedStatusCode(statusCode, location.getValue());
auditor.audit("dispatch", outboundRequest.getURI().toString(), "uri", "success", RES.responseStatus(statusCode));
else
auditor.audit("dispatch", outboundRequest.getURI().toString(), "uri", "unavailable");
return inboundResponse;
protected HttpEntity createRequestEntity(HttpServletRequest request)
throws IOException
String contentType = request.getContentType();
int contentLength = request.getContentLength();
InputStream contentStream = request.getInputStream();
HttpEntity entity;
if (contentType == null)
entity = new InputStreamEntity(contentStream, contentLength);
else
entity = new InputStreamEntity(contentStream, contentLength, ContentType.parse(contentType));
return entity;
java json ndjson
I am working on a http Gateway code to make a patch.
The problem: an application send http request with content type "application/json" but their body has a multiple json. My work is to filter and rewrite this type of http request by:
- Extract the Json body
- Rewrite the Json body to be in NEWLINE Delimited Format (NDJSON)
- Change the content type to "application/x-ndjson"
I tried to change only the content-typebut doesn't solve the problem, because the body was received in bad format.
bad body received with simple json: "content-type"="application/json",
json body 1 json body 2 json body 3
correct body with multiple json: content-type="application/x-ndjson", should be in this format
json body 1 NEWLINE
json body 2 NEWLINE
json body 3 NEWLINE
NEWLINE
Here's my Code:
import com.google.common.collect.Lists;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Enumeration;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.hadoop.gateway.SpiGatewayMessages;
import org.apache.hadoop.gateway.SpiGatewayResources;
import org.apache.hadoop.gateway.audit.api.Auditor;
import org.apache.hadoop.gateway.dispatch.DefaultDispatch;
import org.apache.hadoop.gateway.i18n.messages.MessagesFactory;
import org.apache.hadoop.gateway.i18n.resources.ResourcesFactory;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.StatusLine;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.InputStreamEntity;
import org.apache.http.client.methods.RequestBuilder;
public class ElasticsearchDispatch
extends DefaultDispatch
protected static SpiGatewayMessages LOG = (SpiGatewayMessages)MessagesFactory.get(SpiGatewayMessages.class);
protected static SpiGatewayResources RES = (SpiGatewayResources)ResourcesFactory.get(SpiGatewayResources.class);
public ElasticsearchDispatch()
protected void executeRequest(HttpUriRequest outboundRequest, HttpServletRequest inboundRequest, HttpServletResponse outboundResponse)
throws IOException
List<String> excludeHeaders = Lists.newArrayList(new String "Content-Length" );
Enumeration<String> headersName = inboundRequest.getHeaderNames();
while (headersName.hasMoreElements())
String headerName = (String)headersName.nextElement();
if ((outboundRequest.getHeaders(headerName).length == 0) && (!excludeHeaders.contains(headerName)))
outboundRequest.addHeader(headerName, inboundRequest.getHeader(headerName));
HttpResponse inboundResponse = executeOutboundRequest(outboundRequest);
writeOutboundResponse(outboundRequest, inboundRequest, outboundResponse, inboundResponse);
private HttpUriRequest removeParameter(HttpUriRequest request, String param) throws URISyntaxException
URI uri = request.getURI();
URIBuilder builder = new URIBuilder(uri);
List<NameValuePair> nameValuePairs = builder.getQueryParams();
if ((nameValuePairs != null) && (!nameValuePairs.isEmpty()))
builder.clearParameters();
for (NameValuePair nvp : nameValuePairs)
if (!param.equals(nvp.getName()))
builder.setParameter(nvp.getName(), nvp.getValue());
((HttpRequestBase)request).setURI(builder.build());
return request;
protected HttpResponse executeOutboundRequest(HttpUriRequest outboundRequest) throws IOException
LOG.dispatchRequest(outboundRequest.getMethod(), outboundRequest.getURI());
HttpResponse inboundResponse = null;
try
inboundResponse = client.execute(removeParameter(outboundRequest, "doAs"));
catch (IOException e)
LOG.dispatchServiceConnectionException(outboundRequest.getURI(), e);
auditor.audit("dispatch", outboundRequest.getURI().toString(), "uri", "failure");
throw new IOException(RES.dispatchConnectionError());
catch (URISyntaxException e)
e.printStackTrace();
finally
if (inboundResponse != null)
int statusCode = inboundResponse.getStatusLine().getStatusCode();
if (statusCode != 201)
LOG.dispatchResponseStatusCode(statusCode);
else
Header location = inboundResponse.getFirstHeader("Location");
if (location == null)
LOG.dispatchResponseStatusCode(statusCode);
else
LOG.dispatchResponseCreatedStatusCode(statusCode, location.getValue());
auditor.audit("dispatch", outboundRequest.getURI().toString(), "uri", "success", RES.responseStatus(statusCode));
else
auditor.audit("dispatch", outboundRequest.getURI().toString(), "uri", "unavailable");
return inboundResponse;
protected HttpEntity createRequestEntity(HttpServletRequest request)
throws IOException
String contentType = request.getContentType();
int contentLength = request.getContentLength();
InputStream contentStream = request.getInputStream();
HttpEntity entity;
if (contentType == null)
entity = new InputStreamEntity(contentStream, contentLength);
else
entity = new InputStreamEntity(contentStream, contentLength, ContentType.parse(contentType));
return entity;
java json ndjson
java json ndjson
asked Nov 15 '18 at 15:50
R.LamR.Lam
11
11
add a comment |
add a comment |
0
active
oldest
votes
Your Answer
StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "1"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53323127%2fhandle-body-json-and-content-type-of-httpservletrequest%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
0
active
oldest
votes
0
active
oldest
votes
active
oldest
votes
active
oldest
votes
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53323127%2fhandle-body-json-and-content-type-of-httpservletrequest%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown