• (disco) in reply to ben_lubar

    I think @chubertdev wins. He only used 2 lines to your 3. So much for your Leader-ness.

  • (disco) in reply to abarker

    @aliceif used one line, so I think she wins. Unless someone wants to try to do it in 0 lines.

  • (disco) in reply to ben_lubar
    // there is no setvalue
    
  • (disco) in reply to ben_lubar

    Hey, I use one line, and I did it frist:

    abarker:
    setvalue = (testValue == true) ? 0 : 42;

    Unless you're saying that ternary operators are disallowed.

  • (disco) in reply to abarker
    setvalue =  !testValue * 42;
    
  • (disco) in reply to boomzilla

    That only works in languages which permit implicit casts from boolean to int (or some other numeric).

  • (disco)

    I took this books advice a long time ago, http://en.wikipedia.org/wiki/The_Elements_of_Programming_Style -> be clear, don't use tricks.

    Ternary operators have to be tiny phrases to be readable.

    I'll try refactoring the given code for clarity based on Vivek's breakdown

    if failsafe == 0 { error = "No technical alarms" else error = "" if failsafe & 1 concat( error, "Detection zones staying in a given state;" ) if failsafe & 2 concat ( error, "Bad visibility;" ) if failsafe & 4 concat ( error, "Initialization;" ) if failsafe & 8 concat ( error, "Bad configuration;" ) endif

  • (disco) in reply to abarker

    And the ternary only works in languages with ternary operators...

  • (disco)

    One I use often in PHPTRWTF:

    $var = ( isset($_GET['var']) ) ? $_GET['var'] : DEFAULT_VALUE;
    

    Properly formatted I find it more readable when I have like 4 or 5 of those in a row.

  • (disco) in reply to abarker
    if (testValue) setvalue = 0; else setvalue = 42;
    

    Also one line. What do I win?

  • (disco) in reply to Onyx
    Onyx:
    $var = ( isset($_GET['var']) ) ? $_GET['var'] : DEFAULT_VALUE;

    Oh man, I could see this:

    $var = ( isset($_GET['var']) ) ? $_GET['var'] : $var;
    
  • (disco) in reply to chubertdev

    And I fucked that example up because I never call the variable and parameter the same, for the exact reason of avoiding confusion.

    And then I do it in pedantic dickville. Figures.

  • (disco) in reply to Onyx
    Onyx:
    And I fucked that example up because I never call the variable and parameter the same, for the exact reason of avoiding confusion.

    And then I do it in pedantic dickville. Figures.

    No pressure or anything.

  • (disco) in reply to Keith
    for ($setvalue = 0; $setvalue <= 41 && !$testvalue; $setvalue++);
    
  • a e (unregistered)

    Discourse aside..... WHile I think ternary operators are overused, I think are occasionally useful for succinctness without losing readability, eg:

    print "you have ${NUM} carrot".${NUM}==1?"":"s"."left"

    or even: printf("The answer is %d\n", x?0:*x);

  • (disco) in reply to johnatwork

    That's not clear at all. What language is that, anyway? It seems to be missing like 5 endifs and a lot of parentheses.

  • (disco) in reply to Captain

    It's the open bracket followed by an "endif" instead of a close bracket that really gets me.

  • (disco)

    Then there are languages (probably older than most of us) that allow: a := if b = 5 then 0 else 42;

    This language is over 50 years old!

  • (disco)

    (define setvalue (or (and testvalue 0) 42))

  • (disco)
    SELECT IF(setvalue = '42', 1, 0) AS LUE
    

    Note: MySQL, didn't check other engines


    Filed under: FROM dual

  • (disco) in reply to Onyx

    a := 6 * 9 == 42;

  • (disco) in reply to mruhlin

    If you have a case where you might actually care about the performance of a few string concatenations, you should be returning the bit field, not a string representation of it.

  • (disco) in reply to boomzilla
    int setvalue = (*(&0["*"]))%('*'+(!testvalue));
    
  • (disco)

    The most common use for the ? operator I've had comes in very handy in slicing and math-like operations.

    For instance (all variables are integers)

    slice_size = num_slices / num_elements + ( num_slices % num_elements ? 1 : 0);

    This is a very common idiom in SIMD code.

    That being said, yeah, the submitter's line is all kinds of WTF.

  • (disco) in reply to Onyx
    Onyx:
    `SELECT IF(setvalue = '42', 1, 0) AS LUE`

    Note: MySQL, didn't check other engines

    I think standard SQL is more like: ```sql SELECT CASE setvalue WHEN '42' THEN 1 ELSE 0 END AS LUE ``` (Yes, it's not _quite_ the same thing…)
  • (disco) in reply to johnatwork

    In Java, I found that I can replace this beauty

                final String result =
                    FailSafe == 0 ? "No technical alarms" :
                    ((FailSafe & 1) != 0 && (FailSafe & 2) != 0 && (FailSafe & 4) != 0 && (FailSafe & 8) != 0 ? "Detection zones staying in a given state; Bad visibility; Initialization; Bad configuration" :
                    ((FailSafe & 1) != 0 && (FailSafe & 2) != 0 && (FailSafe & 4) != 0 ? "Detection zones staying in a given state; Bad visibility; Initialization" :
                    ((FailSafe & 1) != 0 && (FailSafe & 2) != 0 && (FailSafe & 8) != 0 ? "Detection zones staying in a given state; Bad visibility; Bad configuration" :
                    ((FailSafe & 1) != 0 && (FailSafe & 4) != 0 && (FailSafe & 8) != 0 ? "Detection zones staying in a given state; Initialization; Bad configuration" :
                    ((FailSafe & 2) != 0 && (FailSafe & 4) != 0 && (FailSafe & 8) != 0 ? "Bad visibility; Initialization; Bad configuration" :
                    ((FailSafe & 1) != 0 && (FailSafe & 2) != 0 ? "Detection zones staying in a given state; Bad visibility" :
                    ((FailSafe & 1) != 0 && (FailSafe & 4) != 0 ? "Detection zones staying in a given state; Initialization" :
                    ((FailSafe & 1) != 0 && (FailSafe & 8) != 0 ? "Detection zones staying in a given state; Bad configuration" :
                    ((FailSafe & 2) != 0 && (FailSafe & 4) != 0 ? "Bad visibility; Initialization" :
                    ((FailSafe & 2) != 0 && (FailSafe & 8) != 0 ? "Bad visibility; Bad configuration" :
                    ((FailSafe & 4) != 0 && (FailSafe & 8) != 0 ? "Initialization; Bad configuration" :
                    ((FailSafe & 1) != 0 ? "Detection zones staying in a given state" :
                    ((FailSafe & 2) != 0 ? "Bad visibility" :
                    ((FailSafe & 4) != 0 ? "Initialization" :
                    ((FailSafe & 8) != 0 ? "Bad configuration" :
                    "Unknown")))))))))))))));
    

    with this code

            final StringBuilder sb = new StringBuilder();
        if ((FailSafe & 1) != 0) sb.append("Detection zones staying in a given state; ");
        if ((FailSafe & 2) != 0) sb.append("Bad visibility; ");
        if ((FailSafe & 4) != 0) sb.append("Initialization; ");
        if ((FailSafe & 8) != 0) sb.append("Bad configuration; ");
        if (sb.length() == 0)
            sb.append("No technical alarms");
        else
            sb.setLength(sb.length() - 2);
        return sb.toString();
    

    Personally, I like the second much better.

  • Jim the Tool (unregistered)

    The real WTF is that Intercourse (sorry, discourse) doesn't even let me view comments without JavaScript now. At least before I could read the comments even with JS disabled. Now...

    Well, fuck that I ain't enabling JS for this site, 'cause it's not needed. At all.

    Captcha minim. The minim you need, is for the bloody thing to work without JavaScript enabled.

  • (disco) in reply to boomzilla
    setvalue = testValue && 42;
    

    Pretty sure I've seen this in the wild, too. Only works in languages designed for such horrible things.

  • (disco) in reply to brymck

    What happens if testValue is @FILE_NOT_FOUND?

  • (disco) in reply to ben_lubar

    I'm more concerned about testValue being @mikeTheLiar.

  • n/a (unregistered) in reply to a e
    a e:
    Discourse aside..... WHile I think ternary operators are overused, I think are occasionally useful for succinctness without losing readability, eg:

    print "you have ${NUM} carrot".${NUM}==1?"":"s"."left"

    Your example is a TRWTF, since it's instanly impossible to localise correctly. Gah, I hate coders who would think this is a good way to add plurals, even as a throw-away sample.

  • (disco) in reply to ben_lubar

    variable = (test_value == FILE_NOT_FOUND ? default_value) && true_value

    But personally, I would introduce a WTF operator:

    variable = test_value !? fnf_value : true_value : false_value

    You can also use the plain old ? as the WTF operator, since they require a different number of arguments.

  • (disco) in reply to FILE_NOT_FOUND
    FILE_NOT_FOUND:
    `!?`

    Unfortunately, getting the icon right means breaking valid syntax.

    x ? !y : z;

    Therefore, we are removing the unary negation operator from the language.

  • Guestimate (unregistered) in reply to Jim the Tool
    Jim the Tool:
    At least before I could read the comments even with JS disabled. Now...
    And that might quite literally be the problem: By disabeling JS you/we also do not get to see all those advertisements from which this site probably makes (part of) its income.

    When discourse/JS is used for all comments this site will probably lose its attraction to me, after which it gets removed from my list.

    Oh well, such is life.

  • (cs) in reply to Guestimate
    Guestimate:
    By disabeling JS you/we also do not get to see all those advertisements from which this site probably makes (part of) its income.
    Adverts which require JS are also a major WTF. Given that JS adverts are a noted vector of malware, anyone who allows them is either ignorant or crazy, and the same goes for anyone who relies on them.
  • (disco) in reply to ben_lubar

    Well if we survived C++ getting rid of the most vexing parse, I'm sure making a special case for ?! x : y : z vs ? !x : y : z won't be a problem.

  • Guestimate (unregistered) in reply to pjt33
    pjt33:
    Adverts which require JS are also a major WTF.
    From a client perspective I do not understand that either. From a supplier POV I see a number of advantages.
    pjt33:
    Given that JS adverts are a noted vector of malware,
    Just as JS or any kind of active content from any source can be. Its just that advertisement networks currently have the largest spread.
    pjt33:
    anyone who allows them is either ignorant or crazy,
    Go tell that to the facebook (and alike) crowd. They have no idea what the fuzz is all about and will still not comprehend it -- or even consider it -- when its explained to them. They do not care, as "it will never happen to them". Until it does ofcourse.
    pjt33:
    and the same goes for anyone who relies on them.
    Again, producers and users POV. It certainly works (in several ways) for someone creating it and sending it off to the user. For the user, not so much ...

    Fun fact: when a user just installs stuff from random places and gets hit by spware, malware or viri its ofcourse his own fault, as he should have choosen more reliable sources.
    If however the same person doesn't allow JS, flash and other active content like it also coming from random sources he's the odd-one-out. Go figure. :-)

    @People of WTF: Is it really that hard to return a bit more specific error when someone uses true HTML tags ? The way its put it could have been anything, including stuff nothing to do with the post itself. :-\

  • CigarDoug (unregistered) in reply to n/a
    n/a:
    a e:
    Discourse aside..... WHile I think ternary operators are overused, I think are occasionally useful for succinctness without losing readability, eg:

    print "you have ${NUM} carrot".${NUM}==1?"":"s"."left"

    Your example is a TRWTF, since it's instanly impossible to localise correctly. Gah, I hate coders who would think this is a good way to add plurals, even as a throw-away sample.

    1. Localization is only important when the requirements say it is. I happily don't have to give a second thought to localization because the eyeballs that see the results of my code are a very limited group. Ditto for browser compatibility. If everyone uses IE8 (ugh) in your organization, it's at least one less thing to look out for.

    2. Please provide a one line example that is BETTER at expressing "0 carrots", "1 carrot", "2 carrots". Seriously. I really want to know a better way to do this. Ternary solutions, used sparingly, can be quite elegant.

  • ratis (unregistered) in reply to CigarDoug
    CigarDoug:
    2. Please provide a one line example that is BETTER at expressing "0 carrots", "1 carrot", "2 carrots". Seriously. I really want to know a better way to do this. Ternary solutions, used sparingly, can be quite elegant.
    Since you just care about English, Lingu::EN::Inflect.
  • (disco) in reply to herby

    Scala lets you do

    val a = if( b == 5 ) 0 else 42
    
  • (disco)

    I'm surprised, over 24 hours later and still no one has posted the REAL wtf: magic constants!

    I've fixed this problem in the original code and it is much more readable:

    #define DETECTION_ZONES_STAYING_IN_A_GIVEN_STATE 1
    #define BAD_VISIBILITY 2
    #define INITIALIZATION 4
    #define BAD_CONFIGURATION 8
    FailSafe==0?'No technical alarms':((FailSafe&DETECTION_ZONES_STAYING_IN_A_GIVEN_STATE)!=0&&(FailSafe&BAD_VISIBILITY)!=0&&(FailSafe&INITIALIZATION)!=0&&(FailSafe&BAD_CONFIGURATION)!=0?'Detection zones staying in a given state; Bad visibility;
    Initialization; Bad configuration':((FailSafe&DETECTION_ZONES_STAYING_IN_A_GIVEN_STATE)!=0&&(FailSafe&BAD_VISIBILITY)!=0&&(FailSafe&INITIALIZATION)!=0?'Detection zones staying in a given state; Bad visibility; Initialization':
    ((FailSafe&DETECTION_ZONES_STAYING_IN_A_GIVEN_STATE)!=0&&(FailSafe&BAD_VISIBILITY)!=0&&(FailSafe&BAD_CONFIGURATION)!=0?'Detection zones staying in a given state; Bad visibility; Bad configuration':((FailSafe&DETECTION_ZONES_STAYING_IN_A_GIVEN_STATE)!=0&&(FailSafe&INITIALIZATION)!=0&&
    (FailSafe&BAD_CONFIGURATION)!=0?'Detection zones staying in a given state; Initialization; Bad configuration':((FailSafe&BAD_VISIBILITY)!=0&&(FailSafe&INITIALIZATION)!=0&&(FailSafe&BAD_CONFIGURATION)!=0?'Bad visibility;
    Initialization; Bad configuration':((FailSafe&DETECTION_ZONES_STAYING_IN_A_GIVEN_STATE)!=0&&(FailSafe&BAD_VISIBILITY)!=0?'Detection zones staying in a given state; Bad visibility':((FailSafe&DETECTION_ZONES_STAYING_IN_A_GIVEN_STATE)!=0&&(FailSafe&INITIALIZATION)!=0?'Detection 
    zones staying in a given state; Initialization':((FailSafe&DETECTION_ZONES_STAYING_IN_A_GIVEN_STATE)!=0&&(FailSafe&BAD_CONFIGURATION)!=0?'Detection zones staying in a given state; Bad configuration':((FailSafe&BAD_VISIBILITY)!=0&&
    (FailSafe&INITIALIZATION)!=0?'Bad visibility; Initialization':((FailSafe&BAD_VISIBILITY)!=0&&(FailSafe&BAD_CONFIGURATION)!=0?'Bad visibility; Bad configuration':((FailSafe&INITIALIZATION)!=0&&(FailSafe&BAD_CONFIGURATION)!=0?'Initialization; Bad 
    configuration':((FailSafe&DETECTION_ZONES_STAYING_IN_A_GIVEN_STATE)!=0?'Detection zones staying in a given state':((FailSafe&BAD_VISIBILITY)!=0?'Bad visibility':((FailSafe&INITIALIZATION)!=0?'Initialization':((FailSafe&BAD_CONFIGURATION)!=0?'Bad 
    configuration':'Unknown')))))))))))))))
    
  • (disco) in reply to dcotvpu2jb8n8
    #define DETECTION_ZONES_STAYING_IN_A_GIVEN_STATE 1
    #define BAD_VISIBILITY 2
    #define INITIALIZATION 4
    #define BAD_CONFIGURATION 8
    FailSafe==0?'No technical alarms':((FailSafe&DETECTION_ZONES_STAYING_IN_A_GIVEN_STATE)!=0&&(FailSafe&BAD_VISIBILITY)!=0&&(FailSafe&INITIALIZATION)!=0&&(FailSafe&BAD_CONFIGURATION)!=0?'Detection zones staying in a given state; Bad visibility;
    Initialization; Bad configuration':((FailSafe&DETECTION_ZONES_STAYING_IN_A_GIVEN_STATE)!=0&&(FailSafe&BAD_VISIBILITY)!=0&&(FailSafe&INITIALIZATION)!=0?'Detection zones staying in a given state; Bad visibility; Initialization':
    ((FailSafe&DETECTION_ZONES_STAYING_IN_A_GIVEN_STATE)!=0&&(FailSafe&BAD_VISIBILITY)!=0&&(FailSafe&BAD_CONFIGURATION)!=0?'Detection zones staying in a given state; Bad visibility; Bad configuration':((FailSafe&DETECTION_ZONES_STAYING_IN_A_GIVEN_STATE)!=0&&(FailSafe&INITIALIZATION)!=0&&
    (FailSafe&BAD_CONFIGURATION)!=0?'Detection zones staying in a given state; Initialization; Bad configuration':((FailSafe&BAD_VISIBILITY)!=0&&(FailSafe&INITIALIZATION)!=0&&(FailSafe&BAD_CONFIGURATION)!=0?'Bad visibility;
    Initialization; Bad configuration':((FailSafe&DETECTION_ZONES_STAYING_IN_A_GIVEN_STATE)!=0&&(FailSafe&BAD_VISIBILITY)!=0?'Detection zones staying in a given state; Bad visibility':((FailSafe&DETECTION_ZONES_STAYING_IN_A_GIVEN_STATE)!=0&&(FailSafe&INITIALIZATION)!=0?'Detection 
    zones staying in a given state; Initialization':((FailSafe&DETECTION_ZONES_STAYING_IN_A_GIVEN_STATE)!=0&&(FailSafe&BAD_CONFIGURATION)!=0?'Detection zones staying in a given state; Bad configuration':((FailSafe&BAD_VISIBILITY)!=0&&
    (FailSafe&INITIALIZATION)!=0?'Bad visibility; Initialization':((FailSafe&BAD_VISIBILITY)!=0&&(FailSafe&BAD_CONFIGURATION)!=0?'Bad visibility; Bad configuration':((FailSafe&INITIALIZATION)!=0&&(FailSafe&BAD_CONFIGURATION)!=0?'Initialization; Bad 
    configuration':((FailSafe&DETECTION_ZONES_STAYING_IN_A_GIVEN_STATE)!=0?'Detection zones staying in a given state':((FailSafe&BAD_VISIBILITY)!=0?'Bad visibility':((FailSafe&INITIALIZATION)!=0?'Initialization':((FailSafe&BAD_CONFIGURATION)!=0?'Bad 
    configuration':'Unknown')))))))))))))))
    

    There. Much more readable.


    Filed under: shipit!

  • (disco)

    I agree 100% with article-writer Mark Bow-Ties. Clearly the problem is the ternary statements, not the fact that it's an unnecessarily long case analysis which has been packed into one line! For if you just use && and || things get so much better!      FailSafe==0&&'No technical alarms'||((FailSafe&1)!=0&&(FailSafe&2)!=0&&(FailSafe&4)!=0&&(FailSafe&8)!=0&&'Detection zones staying in a given state; Bad visibility; Initialization; Bad configuration'||((FailSafe&1)!=0&&(FailSafe&2)!=0&&(FailSafe&4)!=0&&'Detection zones staying in a given state; Bad visibility; Initialization'||((FailSafe&1)!=0&&(FailSafe&2)!=0&&(FailSafe&8)!=0&&'Detection zones staying in a given state; Bad visibility; Bad configuration'||((FailSafe&1)!=0&&(FailSafe&4)!=0&&(FailSafe&8)!=0&&'Detection zones staying in a given state; Initialization; Bad configuration'||((FailSafe&2)!=0&&(FailSafe&4)!=0&&(FailSafe&8)!=0&&'Bad visibility; Initialization; Bad configuration'||((FailSafe&1)!=0&&(FailSafe&2)!=0&&'Detection zones staying in a given state; Bad visibility'||((FailSafe&1)!=0&&(FailSafe&4)!=0&&'Detection zones staying in a given state; Initialization'||((FailSafe&1)!=0&&(FailSafe&8)!=0&&'Detection zones staying in a given state; Bad configuration'||((FailSafe&2)!=0&&(FailSafe&4)!=0&&'Bad visibility; Initialization'||((FailSafe&2)!=0&&(FailSafe&8)!=0&&'Bad visibility; Bad configuration'||((FailSafe&4)!=0&&(FailSafe&8)!=0&&'Initialization; Bad configuration'||((FailSafe&1)!=0&&'Detection zones staying in a given state'||((FailSafe&2)!=0&&'Bad visibility'||((FailSafe&4)!=0&&'Initialization'||((FailSafe&8)!=0&&'Bad configuration'||'Unknown'))))))))))))))

    Compare that to this filth:

    FailSafe == 0 ? 'No technical alarms' :
        FailSafe & 0xF ? (
            (FailSafe & 1 ? 'Detection zones staying in a given state; ' : '') +
            (FailSafe & 2 ? 'Bad visibility; ' : '') +
            (FailSafe & 4 ? 'Initialization; ' : '') +
            (FailSafe & 8 ? 'Bad configuration; ' : '')
        ).slice(0, -2) : 'Unknown' /* slice removes trailing '; ' */
    

    The question marks just stare at you, questioningly. It's enough to drive a sane developer mad.

  • (disco) in reply to brymck

    It would be setValue = testValue || 42;, common in Javascript ... And it's a shorthand that grows on you. It makes some sense, it's a logical extension of boolean expressions being short-circuited and the fact that values of any type can be "falsy" (if they are 0, '', null, undefined, NaN, or false), or "truthy" (if they are not falsy). The a || b operator can be equivalently rewritten a ? a : b, likewise the a && b can be rewritten a ? b : a.

    Only thing you have to be sure of is that testValue can't be a value that is both falsy and valid. If 0 is a valid value, you'll accidentally overwrite it with the default.

  • foo AKA fooo (unregistered) in reply to CigarDoug
    CigarDoug:
    2. Please provide a one line example that is BETTER at expressing "0 carrots", "1 carrot", "2 carrots". Seriously. I really want to know a better way to do this. Ternary solutions, used sparingly, can be quite elegant.
    printf (ngettext ("%i carrot", "%i carrots", n), n);
  • (disco) in reply to bishoprook

    In the original setValue equals 0 if testValue is false (in C and Perl or some shells with $s thrown in). So when the first test succeeds the expression continues to 42, which is also true, and then returns that final value. If testValue is false, then the expression returns whatever represents falseness in that language, which for C/Perl/whatever is 0, so it's abusing the Boolean and integer nature of 0.

    a = b || c is perfectly idiomatic in several languages, but it's different from what I'm trying to do above.

  • (disco) in reply to faoileag

    But not on embedded devices!

  • (disco) in reply to BlueGiant
    BlueGiant:
    The most common use for the ? operator I've had comes in very handy in slicing and math-like operations.

    For instance (all variables are integers)

    slice_size = num_slices / num_elements + ( num_slices % num_elements ? 1 : 0);

    This is a very common idiom in SIMD code.

    That being said, yeah, the submitter's line is all kinds of WTF.

    ` slice_size = (num_slices + num_elements - 1)/num_elements;` or ` slice_size = num_slices / num_elements + (num_slices % num_elements != 0);`

    Given that, if I've read it correctly(*), you are calculating (int)ceil(num_slices/(double)num_elements);.

    (*) This is my major beef with ternaries (especially with abbreviated conditions) - they make the code harder to read. I'd generally prefer my second alternative for readability but the other one for SISD performance (avoids having both / and %, although this might not be relevant on x86, which calculates both when executing a machine language integer divide instruction, so the % is basically "free").

  • (disco) in reply to Steve_The_Cynic
    Steve_The_Cynic:
    (*) This is my major beef with ternaries (especially with abbreviated conditions) - they make the code harder to read.

    This really depends. I tend to use ternaries mostly in repeated situations that lead to short, readable code because you know what's coming. ie: (php this time, but it applies in any language that you need to do null types of checks to load a variable)

    $a = isset($_POST["a"]) ? $_POST["a"] : $someDefaultForA;
    ....
    $z = isset($_POST["z"]) ? $_POST["z"] : $someDefaultForZ;
    

    Since you know after the first line that the whole thing is the same repeated logic, it's way easier to read than the multiple lines it takes to do an if/then/else block.


    Filed Under: In before "why didn't you use array_key_exists?", and "PHP is TRWTF".
  • (disco) in reply to darkmatter
    darkmatter:
    Filed Under: In before "why didn't you use array_key_exists?", and "PHP is TRWTF".

    array_key_exists takes about ten times as long as isset does, according to a comment on the documentation page.

Leave a comment on “One Bad Ternary Operator Deserves Another”

Log In or post as a guest

Replying to comment #:

« Return to Article