Merging Hot Flux SourcesActiveMQ some consumers not picking up tasks if they arrive after producerwhy spill failure happens for Custom Data Type in HadoopWhy does JMockIt mock the getter X.getE() for class X in this snippet?Error:java: javacTask: source release 8 requires target release 1.8Working with Flux in a Scheduled TaskHow to map a flux with mono?Dynamically merging FluxesMerge Flux emissions with duplication?Flux from WebClient behaves differently than Flux from File.readLinesHow to use groupBy on a hot source
What is this airplane?
AMPScript SMS InsertDE() function not working in SMS
How can one's career as a reviewer be ended?
Is it expected that a reader will skip parts of what you write?
How creative should the DM let an artificer be in terms of what they can build?
How to “listen” to existing circuit
Has there been a multiethnic Star Trek character?
Increase speed altering column on large table to NON NULL
How to communicate to my GM that not being allowed to use stealth isn't fun for me?
Is using 'echo' to display attacker-controlled data on the terminal dangerous?
If I leave the US through an airport, do I have to return through the same airport?
UTC timestamp format for launch vehicles
What are neighboring ports?
Proving that a Russian cryptographic standard is too structured
Does putting salt first make it easier for attacker to bruteforce the hash?
Russian word for a male zebra
Is it possible to have 2 different but equal size real number sets that have the same mean and standard deviation?
How can I remove material from this wood beam?
Fermat's statement about the ancients: How serious was he?
Who won a Game of Bar Dice?
How do free-speech protections in the United States apply in public to corporate misrepresentations?
A word that means "blending into a community too much"
With Ubuntu 18.04, how can I have a hot corner that locks the computer?
Printing Pascal’s triangle for n number of rows in Python
Merging Hot Flux Sources
ActiveMQ some consumers not picking up tasks if they arrive after producerwhy spill failure happens for Custom Data Type in HadoopWhy does JMockIt mock the getter X.getE() for class X in this snippet?Error:java: javacTask: source release 8 requires target release 1.8Working with Flux in a Scheduled TaskHow to map a flux with mono?Dynamically merging FluxesMerge Flux emissions with duplication?Flux from WebClient behaves differently than Flux from File.readLinesHow to use groupBy on a hot source
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty height:90px;width:728px;box-sizing:border-box;
In Spring Boot 2 with Reactor, I am attempting to merge two Flux hot sources. However, the merge only ever seems to report the first of the two Flux parameters in merge. How do I get the merge to recognize the second Flux.
In the example below, the System.err in B-2 doesn't even print when outgoing1a is the first parameter. If I make outgoing2 the first, then A-2 doesn't print.
Below is the full example;
package com.example.demo;
import java.time.Duration;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import reactor.core.publisher.Flux;
import reactor.core.scheduler.Schedulers;
public class Weather
String city;
Integer temperature;
public Weather(String city, Integer temperature)
this.city = city;
this.temperature = temperature;
@Override
public String toString()
return "Weather [city=" + city + ", temperature=" + temperature + "]";
public static void main(String[] args)
BlockingQueue<Weather> queue = new LinkedBlockingQueue<>();
BlockingQueue<Weather> queue2 = new LinkedBlockingQueue<>();
// Assume Spring @Repository "A-1"
new Thread(() ->
for (int d = 1; d < 1000; d += 1)
for (String s: new String[] "LDN", "NYC", "PAR", "ZUR")
queue.add(new Weather(s, d));
try Thread.sleep(250); catch (InterruptedException e)
).start();
// Assume Spring @Repository "B-1"
new Thread(() ->
for (int d = 1; d < 1000; d += 1)
for (String s: new String[] "MOS", "TLV")
queue2.add(new Weather(s, d));
try Thread.sleep(1000); catch (InterruptedException e)
).start();
// Assume Spring @Service "A-2" = real-time LDN, NYC, PAR, ZUR
Flux<Weather> outgoing1 = Flux.<Weather>create(
sink ->
for (int i = 0; i < 1000; i++)
try
sink.next(queue.take());
System.err.println("1 " + queue.size());
catch (InterruptedException e)
e.printStackTrace();
sink.complete();
).publishOn(Schedulers.newSingle("outgoing-1"));
// Assume Spring @Service "B-2" = real-time MOS, TLV
Flux<Weather> outgoing2 = Flux.<Weather>create(
sink ->
for (int i = 0; i < 1000; i++)
try
sink.next(queue2.take());
System.err.println("2 " + queue2.size());
catch (InterruptedException e)
e.printStackTrace();
sink.complete();
).publishOn(Schedulers.newSingle("outgoing-2"));
// Assume Spring @Service "A-3" = 5 second summary of LDN, NYC, PAR, ZUR
Flux<Weather> outgoing1a = Flux.from(outgoing1)
.groupBy(c -> c.city)
.flatMap(g -> g
.sample(Duration.ofSeconds(5))
)
.log("C");
// Assume Spring @Service "C" - merges "A-3" and "B-2"
// only prints outgoing1a
Flux.merge(outgoing1a, outgoing2).subscribe(System.out::println);
// only prints outgoing2
//Flux.merge(outgoing2, outgoing1a).subscribe(System.out::println);
java spring-webflux project-reactor
add a comment |
In Spring Boot 2 with Reactor, I am attempting to merge two Flux hot sources. However, the merge only ever seems to report the first of the two Flux parameters in merge. How do I get the merge to recognize the second Flux.
In the example below, the System.err in B-2 doesn't even print when outgoing1a is the first parameter. If I make outgoing2 the first, then A-2 doesn't print.
Below is the full example;
package com.example.demo;
import java.time.Duration;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import reactor.core.publisher.Flux;
import reactor.core.scheduler.Schedulers;
public class Weather
String city;
Integer temperature;
public Weather(String city, Integer temperature)
this.city = city;
this.temperature = temperature;
@Override
public String toString()
return "Weather [city=" + city + ", temperature=" + temperature + "]";
public static void main(String[] args)
BlockingQueue<Weather> queue = new LinkedBlockingQueue<>();
BlockingQueue<Weather> queue2 = new LinkedBlockingQueue<>();
// Assume Spring @Repository "A-1"
new Thread(() ->
for (int d = 1; d < 1000; d += 1)
for (String s: new String[] "LDN", "NYC", "PAR", "ZUR")
queue.add(new Weather(s, d));
try Thread.sleep(250); catch (InterruptedException e)
).start();
// Assume Spring @Repository "B-1"
new Thread(() ->
for (int d = 1; d < 1000; d += 1)
for (String s: new String[] "MOS", "TLV")
queue2.add(new Weather(s, d));
try Thread.sleep(1000); catch (InterruptedException e)
).start();
// Assume Spring @Service "A-2" = real-time LDN, NYC, PAR, ZUR
Flux<Weather> outgoing1 = Flux.<Weather>create(
sink ->
for (int i = 0; i < 1000; i++)
try
sink.next(queue.take());
System.err.println("1 " + queue.size());
catch (InterruptedException e)
e.printStackTrace();
sink.complete();
).publishOn(Schedulers.newSingle("outgoing-1"));
// Assume Spring @Service "B-2" = real-time MOS, TLV
Flux<Weather> outgoing2 = Flux.<Weather>create(
sink ->
for (int i = 0; i < 1000; i++)
try
sink.next(queue2.take());
System.err.println("2 " + queue2.size());
catch (InterruptedException e)
e.printStackTrace();
sink.complete();
).publishOn(Schedulers.newSingle("outgoing-2"));
// Assume Spring @Service "A-3" = 5 second summary of LDN, NYC, PAR, ZUR
Flux<Weather> outgoing1a = Flux.from(outgoing1)
.groupBy(c -> c.city)
.flatMap(g -> g
.sample(Duration.ofSeconds(5))
)
.log("C");
// Assume Spring @Service "C" - merges "A-3" and "B-2"
// only prints outgoing1a
Flux.merge(outgoing1a, outgoing2).subscribe(System.out::println);
// only prints outgoing2
//Flux.merge(outgoing2, outgoing1a).subscribe(System.out::println);
java spring-webflux project-reactor
add a comment |
In Spring Boot 2 with Reactor, I am attempting to merge two Flux hot sources. However, the merge only ever seems to report the first of the two Flux parameters in merge. How do I get the merge to recognize the second Flux.
In the example below, the System.err in B-2 doesn't even print when outgoing1a is the first parameter. If I make outgoing2 the first, then A-2 doesn't print.
Below is the full example;
package com.example.demo;
import java.time.Duration;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import reactor.core.publisher.Flux;
import reactor.core.scheduler.Schedulers;
public class Weather
String city;
Integer temperature;
public Weather(String city, Integer temperature)
this.city = city;
this.temperature = temperature;
@Override
public String toString()
return "Weather [city=" + city + ", temperature=" + temperature + "]";
public static void main(String[] args)
BlockingQueue<Weather> queue = new LinkedBlockingQueue<>();
BlockingQueue<Weather> queue2 = new LinkedBlockingQueue<>();
// Assume Spring @Repository "A-1"
new Thread(() ->
for (int d = 1; d < 1000; d += 1)
for (String s: new String[] "LDN", "NYC", "PAR", "ZUR")
queue.add(new Weather(s, d));
try Thread.sleep(250); catch (InterruptedException e)
).start();
// Assume Spring @Repository "B-1"
new Thread(() ->
for (int d = 1; d < 1000; d += 1)
for (String s: new String[] "MOS", "TLV")
queue2.add(new Weather(s, d));
try Thread.sleep(1000); catch (InterruptedException e)
).start();
// Assume Spring @Service "A-2" = real-time LDN, NYC, PAR, ZUR
Flux<Weather> outgoing1 = Flux.<Weather>create(
sink ->
for (int i = 0; i < 1000; i++)
try
sink.next(queue.take());
System.err.println("1 " + queue.size());
catch (InterruptedException e)
e.printStackTrace();
sink.complete();
).publishOn(Schedulers.newSingle("outgoing-1"));
// Assume Spring @Service "B-2" = real-time MOS, TLV
Flux<Weather> outgoing2 = Flux.<Weather>create(
sink ->
for (int i = 0; i < 1000; i++)
try
sink.next(queue2.take());
System.err.println("2 " + queue2.size());
catch (InterruptedException e)
e.printStackTrace();
sink.complete();
).publishOn(Schedulers.newSingle("outgoing-2"));
// Assume Spring @Service "A-3" = 5 second summary of LDN, NYC, PAR, ZUR
Flux<Weather> outgoing1a = Flux.from(outgoing1)
.groupBy(c -> c.city)
.flatMap(g -> g
.sample(Duration.ofSeconds(5))
)
.log("C");
// Assume Spring @Service "C" - merges "A-3" and "B-2"
// only prints outgoing1a
Flux.merge(outgoing1a, outgoing2).subscribe(System.out::println);
// only prints outgoing2
//Flux.merge(outgoing2, outgoing1a).subscribe(System.out::println);
java spring-webflux project-reactor
In Spring Boot 2 with Reactor, I am attempting to merge two Flux hot sources. However, the merge only ever seems to report the first of the two Flux parameters in merge. How do I get the merge to recognize the second Flux.
In the example below, the System.err in B-2 doesn't even print when outgoing1a is the first parameter. If I make outgoing2 the first, then A-2 doesn't print.
Below is the full example;
package com.example.demo;
import java.time.Duration;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import reactor.core.publisher.Flux;
import reactor.core.scheduler.Schedulers;
public class Weather
String city;
Integer temperature;
public Weather(String city, Integer temperature)
this.city = city;
this.temperature = temperature;
@Override
public String toString()
return "Weather [city=" + city + ", temperature=" + temperature + "]";
public static void main(String[] args)
BlockingQueue<Weather> queue = new LinkedBlockingQueue<>();
BlockingQueue<Weather> queue2 = new LinkedBlockingQueue<>();
// Assume Spring @Repository "A-1"
new Thread(() ->
for (int d = 1; d < 1000; d += 1)
for (String s: new String[] "LDN", "NYC", "PAR", "ZUR")
queue.add(new Weather(s, d));
try Thread.sleep(250); catch (InterruptedException e)
).start();
// Assume Spring @Repository "B-1"
new Thread(() ->
for (int d = 1; d < 1000; d += 1)
for (String s: new String[] "MOS", "TLV")
queue2.add(new Weather(s, d));
try Thread.sleep(1000); catch (InterruptedException e)
).start();
// Assume Spring @Service "A-2" = real-time LDN, NYC, PAR, ZUR
Flux<Weather> outgoing1 = Flux.<Weather>create(
sink ->
for (int i = 0; i < 1000; i++)
try
sink.next(queue.take());
System.err.println("1 " + queue.size());
catch (InterruptedException e)
e.printStackTrace();
sink.complete();
).publishOn(Schedulers.newSingle("outgoing-1"));
// Assume Spring @Service "B-2" = real-time MOS, TLV
Flux<Weather> outgoing2 = Flux.<Weather>create(
sink ->
for (int i = 0; i < 1000; i++)
try
sink.next(queue2.take());
System.err.println("2 " + queue2.size());
catch (InterruptedException e)
e.printStackTrace();
sink.complete();
).publishOn(Schedulers.newSingle("outgoing-2"));
// Assume Spring @Service "A-3" = 5 second summary of LDN, NYC, PAR, ZUR
Flux<Weather> outgoing1a = Flux.from(outgoing1)
.groupBy(c -> c.city)
.flatMap(g -> g
.sample(Duration.ofSeconds(5))
)
.log("C");
// Assume Spring @Service "C" - merges "A-3" and "B-2"
// only prints outgoing1a
Flux.merge(outgoing1a, outgoing2).subscribe(System.out::println);
// only prints outgoing2
//Flux.merge(outgoing2, outgoing1a).subscribe(System.out::println);
java spring-webflux project-reactor
java spring-webflux project-reactor
edited Mar 24 at 20:04
lafual
asked Mar 24 at 19:57
lafuallafual
777
777
add a comment |
add a comment |
1 Answer
1
active
oldest
votes
There are a few things at play here.
- Note the following recommendation of the
.mergeoperator...
Note that merge is tailored to work with asynchronous sources or finite sources. When dealing with an infinite source that doesn't already publish on a dedicated Scheduler, you must isolate that source in its own Scheduler, as merge would otherwise attempt to drain it before subscribing to another source.
Your outbound Fluxes use
.publishOn, but that only affects operators chained after the.publishOnoperator. i.e. It doesn't affect anything before the.publishOn. Specifically, it does not affect the thread on which the code in lambda passed toFlux.createexecutes. You can see this if you add.log()before the.publishOnin each of the outbound Fluxes.Your lambda passed to
Flux.createcalls a blocking method (queue.take).
Since you call subscribe(...) on the merged Flux in the main thread, your lambda passed to Flux.create executes in the main thread, and blocks it.
The easiest fix is to use .subscribeOn instead of .publishOn so that your code in the lambda passed to Flux.create operates on a different thread (other than main). This will prevent the main thread from blocking, and allow the merged output from both outbound streams to be interleaved.
Thank you very much for taking the time to answer.subscribeOninstead orpublishOndid indeed fix the issue. I will play with theThread.sleep()which writes to theBlockingQueueand adelay()after themerge()to see which flavor ofsubscribeOnI will ultimately need.
– lafual
Mar 25 at 5:51
add a comment |
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%2f55327981%2fmerging-hot-flux-sources%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
There are a few things at play here.
- Note the following recommendation of the
.mergeoperator...
Note that merge is tailored to work with asynchronous sources or finite sources. When dealing with an infinite source that doesn't already publish on a dedicated Scheduler, you must isolate that source in its own Scheduler, as merge would otherwise attempt to drain it before subscribing to another source.
Your outbound Fluxes use
.publishOn, but that only affects operators chained after the.publishOnoperator. i.e. It doesn't affect anything before the.publishOn. Specifically, it does not affect the thread on which the code in lambda passed toFlux.createexecutes. You can see this if you add.log()before the.publishOnin each of the outbound Fluxes.Your lambda passed to
Flux.createcalls a blocking method (queue.take).
Since you call subscribe(...) on the merged Flux in the main thread, your lambda passed to Flux.create executes in the main thread, and blocks it.
The easiest fix is to use .subscribeOn instead of .publishOn so that your code in the lambda passed to Flux.create operates on a different thread (other than main). This will prevent the main thread from blocking, and allow the merged output from both outbound streams to be interleaved.
Thank you very much for taking the time to answer.subscribeOninstead orpublishOndid indeed fix the issue. I will play with theThread.sleep()which writes to theBlockingQueueand adelay()after themerge()to see which flavor ofsubscribeOnI will ultimately need.
– lafual
Mar 25 at 5:51
add a comment |
There are a few things at play here.
- Note the following recommendation of the
.mergeoperator...
Note that merge is tailored to work with asynchronous sources or finite sources. When dealing with an infinite source that doesn't already publish on a dedicated Scheduler, you must isolate that source in its own Scheduler, as merge would otherwise attempt to drain it before subscribing to another source.
Your outbound Fluxes use
.publishOn, but that only affects operators chained after the.publishOnoperator. i.e. It doesn't affect anything before the.publishOn. Specifically, it does not affect the thread on which the code in lambda passed toFlux.createexecutes. You can see this if you add.log()before the.publishOnin each of the outbound Fluxes.Your lambda passed to
Flux.createcalls a blocking method (queue.take).
Since you call subscribe(...) on the merged Flux in the main thread, your lambda passed to Flux.create executes in the main thread, and blocks it.
The easiest fix is to use .subscribeOn instead of .publishOn so that your code in the lambda passed to Flux.create operates on a different thread (other than main). This will prevent the main thread from blocking, and allow the merged output from both outbound streams to be interleaved.
Thank you very much for taking the time to answer.subscribeOninstead orpublishOndid indeed fix the issue. I will play with theThread.sleep()which writes to theBlockingQueueand adelay()after themerge()to see which flavor ofsubscribeOnI will ultimately need.
– lafual
Mar 25 at 5:51
add a comment |
There are a few things at play here.
- Note the following recommendation of the
.mergeoperator...
Note that merge is tailored to work with asynchronous sources or finite sources. When dealing with an infinite source that doesn't already publish on a dedicated Scheduler, you must isolate that source in its own Scheduler, as merge would otherwise attempt to drain it before subscribing to another source.
Your outbound Fluxes use
.publishOn, but that only affects operators chained after the.publishOnoperator. i.e. It doesn't affect anything before the.publishOn. Specifically, it does not affect the thread on which the code in lambda passed toFlux.createexecutes. You can see this if you add.log()before the.publishOnin each of the outbound Fluxes.Your lambda passed to
Flux.createcalls a blocking method (queue.take).
Since you call subscribe(...) on the merged Flux in the main thread, your lambda passed to Flux.create executes in the main thread, and blocks it.
The easiest fix is to use .subscribeOn instead of .publishOn so that your code in the lambda passed to Flux.create operates on a different thread (other than main). This will prevent the main thread from blocking, and allow the merged output from both outbound streams to be interleaved.
There are a few things at play here.
- Note the following recommendation of the
.mergeoperator...
Note that merge is tailored to work with asynchronous sources or finite sources. When dealing with an infinite source that doesn't already publish on a dedicated Scheduler, you must isolate that source in its own Scheduler, as merge would otherwise attempt to drain it before subscribing to another source.
Your outbound Fluxes use
.publishOn, but that only affects operators chained after the.publishOnoperator. i.e. It doesn't affect anything before the.publishOn. Specifically, it does not affect the thread on which the code in lambda passed toFlux.createexecutes. You can see this if you add.log()before the.publishOnin each of the outbound Fluxes.Your lambda passed to
Flux.createcalls a blocking method (queue.take).
Since you call subscribe(...) on the merged Flux in the main thread, your lambda passed to Flux.create executes in the main thread, and blocks it.
The easiest fix is to use .subscribeOn instead of .publishOn so that your code in the lambda passed to Flux.create operates on a different thread (other than main). This will prevent the main thread from blocking, and allow the merged output from both outbound streams to be interleaved.
answered Mar 24 at 21:14
Phil ClayPhil Clay
81215
81215
Thank you very much for taking the time to answer.subscribeOninstead orpublishOndid indeed fix the issue. I will play with theThread.sleep()which writes to theBlockingQueueand adelay()after themerge()to see which flavor ofsubscribeOnI will ultimately need.
– lafual
Mar 25 at 5:51
add a comment |
Thank you very much for taking the time to answer.subscribeOninstead orpublishOndid indeed fix the issue. I will play with theThread.sleep()which writes to theBlockingQueueand adelay()after themerge()to see which flavor ofsubscribeOnI will ultimately need.
– lafual
Mar 25 at 5:51
Thank you very much for taking the time to answer.
subscribeOn instead or publishOn did indeed fix the issue. I will play with the Thread.sleep() which writes to the BlockingQueue and a delay() after the merge() to see which flavor of subscribeOn I will ultimately need.– lafual
Mar 25 at 5:51
Thank you very much for taking the time to answer.
subscribeOn instead or publishOn did indeed fix the issue. I will play with the Thread.sleep() which writes to the BlockingQueue and a delay() after the merge() to see which flavor of subscribeOn I will ultimately need.– lafual
Mar 25 at 5:51
add a comment |
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%2f55327981%2fmerging-hot-flux-sources%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