• Generic Joe (unregistered)

    And we wonder why adblock/ghostery/priv3/noscript are popular...

  • (cs)

    OK, I call shenanigans on this one - that's got to be written specifically to get onto TDWTF. There's some remarkable stuff in there...

    if ( 0==1 && browsertype!= -1 )

    for a starter... Oo

  • (cs)

    Nice browser compatibility work too (look at the original):

    alert("do stuff for firefox 4");

  • Nick (unregistered)

    I'm going to start using GUIDs, generated each page load, to name my form elements.

  • (cs) in reply to JimM
    JimM:
    OK, I call shenanigans on this one - that's got to be written specifically to get onto TDWTF. There's some remarkable stuff in there...
    if ( 0==1 && browsertype!= -1 )

    for a starter... Oo

    OMFG, just realised - this is a pattern! A few lines earlier there's an "if ( 1==1 && ....) too! So presumably they're checking that the basic foundation of maths hasn't changed before committing their scraped data back to the homeworld?!?!

    Argh, I have to stop reading that code ... it get worse every line... shudder

  • Honnza (unregistered) in reply to Nick
    Nick:
    I'm going to start using GUIDs, generated each page load, to name my form elements.

    Thanks for breaking autocomplete, myfriend

  • Honnza (unregistered) in reply to JimM
    JimM:
    JimM:
    OK, I call shenanigans on this one - that's got to be written specifically to get onto TDWTF. There's some remarkable stuff in there...
    if ( 0==1 && browsertype!= -1 )

    for a starter... Oo

    OMFG, just realised - this is a pattern! A few lines earlier there's an "if ( 1==1 && ....) too! So presumably they're checking that the basic foundation of maths hasn't changed before committing their scraped data back to the homeworld?!?!

    Argh, I have to stop reading that code ... it get worse every line... shudder

    most likely it's meant as an easy way to disable/enable conditions with a change of a single character. Because

    true vs false
    is too big a change, and
    /** vs /**/
    is not auto-scoped (it also messes up else if chains)

  • ANON (unregistered)

    Looks auto-generated to me.

  • Honnza (unregistered)

    ... that being said, I still prefer

    if(true || ...)
    if(false && ...)
    if(...)
    

    or, if you want to obfuscate, you can try some beauties like

    if(11*12==132 && ..) //quick, and no calculator!
    if(11^2>120 && ..) //yep, that's a XOR pretending to be an exponentiation
    ...
    

    (without the comments of course)

  • anonymouse (unregistered) in reply to ANON

    Autogenerated indeed. That's why you get blocks that are ignored by the 1 == 0 lines.

    I never liked this way of generating as, imho, it adds bloat, non executed bloat, but bloat nevertheless.

  • nouanda (unregistered)

    Well at least, if you subcontracted your development to an Elbonian company, with Elbonian naming specs, the tracker would be fooled!

  • Kappa (unregistered)

    Guess how they sleep in javascript? That's right, just loop a bit!

    function pausecomp(millis) 
    {
    	var date = new Date();
    	var curDate = null;
    	do { curDate = new Date(); }
    	while(curDate-date < millis);
    }

    setTimeout is too hard and too asynchronous?

  • Rick (unregistered) in reply to Kappa

    I found it amusing that while they check for a single field named 'Organization' and 'organization', 'Organisation' isn't in there.

    Kappa:
    Guess how they sleep in javascript? That's right, just loop a bit!
    function pausecomp(millis) 
    {
    	var date = new Date();
    	var curDate = null;
    	do { curDate = new Date(); }
    	while(curDate-date < millis);
    }
    setTimeout is too hard and too asynchronous?
    That's not even a sleep, that's a CPU burner. I have JS disabled by default, glad to see yet another reason to keep it that way.
  • LUDUS (unregistered)

    Google would never be evil. Trust your Google.

  • Adam (unregistered)

    Actually, given that Google knows lots about me, sites using Google Analytics and telling Google which page I visit and when is probably just as much of a privacy problem. Given the three-letter agencies are known to be slurping up data from Google (and similar very large companies), this is definitely an issue.

    I suspect what makes it OK is that Everybody Is Doing It; am I right?

  • faoileag (unregistered) in reply to Rick
    Rick:
    I found it amusing that while they check for a single field named 'Organization' and 'organization', 'Organisation' isn't in there.
    Kappa:
    Guess how they sleep in javascript? That's right, just loop a bit!
    function pausecomp(millis) 
    {
    	var date = new Date();
    	var curDate = null;
    	do { curDate = new Date(); }
    	while(curDate-date < millis);
    }
    setTimeout is too hard and too asynchronous?
    That's not even a sleep, that's a CPU burner.
    And it will probably make Firfeox freeze for a few seconds - pausecomp is called with 1000 millisecons inside a loop.
  • faoileag (unregistered) in reply to Kappa
    Kappa:
    Guess how they sleep in javascript? That's right, just loop a bit!
    function pausecomp(millis) 
    {
    	var date = new Date();
    	var curDate = null;
    	do { curDate = new Date(); }
    	while(curDate-date < millis);
    }
    setTimeout is too hard and too asynchronous?
    Funny thing is, they tried setTimeout, then commented it out and used pausecomp instead. And looking at TFM for setTimeout and and their code, yes, you might be right about the "too hard".
  • (cs) in reply to anonymouse
    anonymouse:
    Autogenerated indeed. That's why you get blocks that are ignored by the 1 == 0 lines.

    I'd buy that if there weren't clearly manual amendments to the code, like commented out lines, dubious debugging code, a mix of both (i.e. commented out debugging lines!) etc. There is no way you'd autogenerate stuff like that.

    I'd stick by my first assumption that this is someone deliberately trolling TDWTF, if I hadn't googled Trackalyzer and found indications that this is actually used. Best bet is that it's legacy and hasn't been maintained for a long time, and that most of the companies who used it are now defunct (or have abandoned their old websites) but it's still scary to think that this has actually been used, seriously, at some point.

  • Ruddiger (unregistered)

    This reminds me of this article I came across the other day...

    http://dotnet.dzone.com/articles/automatically-collect-and

    I had to check the date on it wasn't 1st April

  • Doozerboy (unregistered) in reply to ANON
    ANON:
    Looks auto-generated to me.

    It was definitely generated by a complete and utter tool

  • Herwig (unregistered)

    THAT was not worse than THIS!

  • AutocompleteIsTheDevil (unregistered) in reply to Honnza
    Honnza:
    Nick:
    I'm going to start using GUIDs, generated each page load, to name my form elements.

    Thanks for breaking autocomplete, myfriend

    Autocomplete is the Devil anyway! Baaaaad autocomplete!

    Captcha: inhibeo -- Autocomplete should be inhibeo in the browsers!

  • (cs) in reply to Ruddiger
    Ruddiger:
    This reminds me of this article I came across the other day...

    http://dotnet.dzone.com/articles/automatically-collect-and

    I had to check the date on it wasn't 1st April

    Nah, that's just the sort of "clever" cobbling-together of bits and pieces that we know and, um, well, er, not exactly love in so many articles on here. There's an XKCD on the topic of cobbled-together solutions, something about video files, which fits nicely in with the article you pointed us at.

  • (cs) in reply to Steve The Cynic
    Steve The Cynic:
    ... There's an XKCD on the topic ...

    "If they say they've solved their problem, NEVER ask how".

  • faoileag (unregistered) in reply to JimM
    JimM:
    anonymouse:
    Autogenerated indeed. That's why you get blocks that are ignored by the 1 == 0 lines.

    I'd buy that if there weren't clearly manual amendments to the code, like commented out lines, dubious debugging code, a mix of both (i.e. commented out debugging lines!) etc. There is no way you'd autogenerate stuff like that.

    "Autogenerated" can also apply to only some parts of the code. Like, when you run the stuff your webserver delivers through a template engine before delivery.

    Original code:

    <%set ON = 1%>
    <%set Debugging = 1%>
    if (<%Debugging%> == <%ON%>) {...
    

    Delivered code:

    if (1 == 1) {...

    This is quote common in fact.

  • anonymous (unregistered) in reply to Kappa
    Kappa:
    Guess how they sleep in javascript? That's right, just loop a bit!
    function pausecomp(millis) 
    {
    	var date = new Date();
    	var curDate = null;
    	do { curDate = new Date(); }
    	while(curDate-date < millis);
    }
    setTimeout is too hard and too asynchronous?
    Trying to make anything work properly asynchronously in Javascript is a huge pain in the ass. Mostly because there doesn't EXIST a real "sleep" function... blocking until it returns, but not GUI-locking thread-blocking spin-waiting. setTimeout completely trashes your scope, so it forces you to either use a bunch of static/global variables or try to pass them all to the setTimeout callback.
  • Anonymous (unregistered)

    You know it's a good example of a true WTF when the code does the talking and you don't need a Hanzo story wrapped around it.

  • faoileag (unregistered) in reply to Rick
    Rick:
    I found it amusing that while they check for a single field named 'Organization' and 'organization', 'Organisation' isn't in there.
    Might be because the code has been developed in the USA and not every coder makes a distinction between American English and Other English, as Wiktionary (http://en.wiktionary.org/wiki/organisation) does.
  • faoileag (unregistered) in reply to anonymous
    anonymous:
    Trying to make anything work properly asynchronously in Javascript is a huge pain in the ass. Mostly because there doesn't EXIST a real "sleep" function... blocking until it returns, but not GUI-locking thread-blocking spin-waiting. setTimeout completely trashes your scope, so it forces you to either use a bunch of static/global variables or try to pass them all to the setTimeout callback.
    setTimeout is real asyncronicity and if you need a sleep in an asynchroneous function you are doing it wrong.
    var foo = 'hello world!';
    setTimeout(function() { alert(foo); }, 1000);
    
    Does what is expected, shows an alert with "hello world!" in it after one second. foo is locally scoped, so what's your problem?

    Actually, asynchroneous programming with Javascript is really simple as plenty of AJAX-driven webpages prove.

  • Ruddiger (unregistered) in reply to Steve The Cynic
    Steve The Cynic:
    Ruddiger:
    This reminds me of this article I came across the other day...

    http://dotnet.dzone.com/articles/automatically-collect-and

    I had to check the date on it wasn't 1st April

    Nah, that's just the sort of "clever" cobbling-together of bits and pieces that we know and, um, well, er, not exactly love in so many articles on here. There's an XKCD on the topic of cobbled-together solutions, something about video files, which fits nicely in with the article you pointed us at.

    Yes, but it counts more because they felt the need to share it with the world....and I read it, which hurt my eyes.

  • (cs)

    You should've seen the original code. It took 60 seconds to analyze a page. That was unacceptable, so Adam tried Google Analytics and it completed the task in only a few milliseconds. Nigel insisted that he could rewrite the code and not be beholden to Google. Now it only takes 20 seconds to analyze a page.

  • Dave the geographer (unregistered)
    the exec who thankfully stated, "No, we're not putting that on the site."
    That's the real WTF, right? An exec who DIDN'T make a bone-headed, pointy-haired decision?

    CAPTCHA: modo - modo is a polygon and subdivision surface modeling, sculpting, 3D painting, animation and rendering package developed by Luxology, LLC....wait, what?

  • (cs) in reply to nonpartisan
    nonpartisan:
    You should've seen the original code. It took 60 seconds to analyze a page. That was unacceptable, so Adam tried Google Analytics and it completed the task in only a few milliseconds. Nigel insisted that he could rewrite the code and not be beholden to Google. Now it only takes 20 seconds to analyze a page.

    rightly or wrongly, thats just how it was back then. Meanwhile, the president's daughter...

  • Cidolfas (unregistered) in reply to Kappa

    I think the original purpose of that method is to send off an Ajax request and ensure that the request was actually sent out before allowing navigation to the next screen. If the user navigates away, often the Ajax request isn't sufficiently far along for the server to actually receive it before it's killed, and it gets lost. Another project I was on unfortunately did this in order to ensure the user was logged out when they closed their browser. The only other real option to be really really sure is to open a popunder window which closes itself, which is no less of a WTF.

    More of a WTF is that pausecomp seems to be used in totally random situations that have nothing to do with what I just described.

  • (cs) in reply to Steve The Cynic
    Steve The Cynic:
    There's an XKCD on the topic of cobbled-together solutions, something about video files, which fits nicely in with the article you pointed us at.
    Well, probably not the one you remembered, but this xkcd seems somehow related!
  • anonymous (unregistered) in reply to faoileag
    faoileag:
    anonymous:
    Trying to make anything work properly asynchronously in Javascript is a huge pain in the ass. Mostly because there doesn't EXIST a real "sleep" function... blocking until it returns, but not GUI-locking thread-blocking spin-waiting. setTimeout completely trashes your scope, so it forces you to either use a bunch of static/global variables or try to pass them all to the setTimeout callback.
    setTimeout is real asyncronicity and if you need a sleep in an asynchroneous function you are doing it wrong.
    var foo = 'hello world!';
    setTimeout(function() { alert(foo); }, 1000);
    
    Does what is expected, shows an alert with "hello world!" in it after one second. foo is locally scoped, so what's your problem?

    Actually, asynchroneous programming with Javascript is really simple as plenty of AJAX-driven webpages prove.

    Awesome, that works because foo is global and the anonymous function is in the same scope. This doesn't work:
    function test() {
    var foo = "hello world";
    setTimeout(callback, 1000);
    }

    function callback() { alert(foo); }

    test();

    Oh, you wanted recursion? Yeah, you're stuck with a bunch of globals, or passing everything you need from an anonymous function. Exactly like I said before.

  • distineo (unregistered) in reply to anonymous
    anonymous:
    Trying to make anything work properly asynchronously in Javascript is a huge pain in the ass. Mostly because there doesn't EXIST a real "sleep" function... blocking until it returns, but not GUI-locking thread-blocking spin-waiting.
    That's easy, just write a program to transform your code into continuation-passing style, and then setTimeout works just fine. (And yes, I have actually done this....)
  • faoileag (unregistered) in reply to anonymous
    anonymous:
    faoileag:
    anonymous:
    Trying to make anything work properly asynchronously in Javascript is a huge pain in the ass. Mostly because there doesn't EXIST a real "sleep" function... blocking until it returns, but not GUI-locking thread-blocking spin-waiting. setTimeout completely trashes your scope, so it forces you to either use a bunch of static/global variables or try to pass them all to the setTimeout callback.
    setTimeout is real asyncronicity and if you need a sleep in an asynchroneous function you are doing it wrong.
    var foo = 'hello world!';
    setTimeout(function() { alert(foo); }, 1000);
    
    Does what is expected, shows an alert with "hello world!" in it after one second. foo is locally scoped, so what's your problem?
    Awesome, that works because foo is global and the anonymous function is in the same scope.
    No, foo isn't global, foo is just in the same scope as the anonymous function. This is the reason the idiom "var instance = this;" comes in handy when you use anonymous functions in an oo context.
    anonymous:
    This doesn't work:
    function test() {
        var foo = "hello world";
        setTimeout(callback, 1000);
    }
    

    function callback() { alert(foo); }

    test();

    Indeed, it doesn't. Without delving too deep into the stuff, functions are a closed scope and the only way of getting data into that scope from the outside is either by passing arguments or by using global variables or via member variables (in an oo context). This is the same in all languages I know but doesn't really make asynchroneous programming too difficult - either you pass the data around via arguments or you create some global shared data object. The first is probably preferable.

    anonymous:
    Oh, you wanted recursion?
    What's got recursion to do with it?
  • Honnza (unregistered) in reply to anonymous
    anonymous:
    faoileag:
    anonymous:
    Trying to make anything work properly asynchronously in Javascript is a huge pain in the ass. Mostly because there doesn't EXIST a real "sleep" function... blocking until it returns, but not GUI-locking thread-blocking spin-waiting. setTimeout completely trashes your scope, so it forces you to either use a bunch of static/global variables or try to pass them all to the setTimeout callback.
    setTimeout is real asyncronicity and if you need a sleep in an asynchroneous function you are doing it wrong.
    var foo = 'hello world!';
    setTimeout(function() { alert(foo); }, 1000);
    
    Does what is expected, shows an alert with "hello world!" in it after one second. foo is locally scoped, so what's your problem?

    Actually, asynchroneous programming with Javascript is really simple as plenty of AJAX-driven webpages prove.

    Awesome, that works because foo is global and the anonymous function is in the same scope. This doesn't work:
    function test() {
    var foo = "hello world";
    setTimeout(callback, 1000);
    }

    function callback() { alert(foo); }

    test();

    Oh, you wanted recursion? Yeah, you're stuck with a bunch of globals, or passing everything you need from an anonymous function. Exactly like I said before.

    the that foo is global is not needed in the example. Even if callback is outside test, you can do this:

    function callback(foo){...};
    function test(){
      var foo = "Hello World!";
      setTimeout(function(){
        callback(foo)
      })
    }
    

    or even, in ES5,

    function callback(foo){...};
    function test(){
      var foo = "Hello World";
      setTimeout(callback.bind(null, foo));
    }
    

    If you want recursion, you can use nested functions, even immediately invoked functions

    function deepSum(tree){
      var sum = 0;
      (function doDeepSum(node){
        if(typeof node == "number") sum += node;
        else node.forEach(doDeepSum)
      }(tree))
      return sum
    }
    
    function getPageCount(url){
      var count = 1;
      (function fetchPage(url, callback){
        $.getHTML(url, function(result){
          $nextA = $("a.nextPage", result)
          if($nextA.length){
            count++;
            fetchPage($nextA.attr("href"));
          } else callback(count);
        });
      }(url));
    }
    

    Closures are an amazing stuff.

    Java doesn't let you close over non-final variables, but you can still close over instance fields or do

     Stuff[] stuff = {stuff}; 

    In C, you'd probably pass a pointer to a structure where you can keep your data. When the library finishes doing the asynchronous stuff, it then passes the sole pointer as an argument to the callback.

    void notify(void (callback)(T))

  • (cs) in reply to JimM
    JimM:
    OMFG, just realised - this is a pattern! A few lines earlier there's an "if ( 1==1 && ....) too! So presumably they're checking that the basic foundation of maths hasn't changed before committing their scraped data back to the homeworld?!?!
    It's just good thinking. You never know what kind of Universe your clients are going to be contacting you from so it's important to check those things. If you don't you run the risk of dividing a prime number by three and creating a singularity which could destroy everything.
  • Lord Lordship. (unregistered) in reply to faoileag
    faoileag:
    Rick:
    I found it amusing that while they check for a single field named 'Organization' and 'organization', 'Organisation' isn't in there.
    Might be because the code has been developed in the USA and not every coder makes a distinction between American English and Other English, as Wiktionary (http://en.wiktionary.org/wiki/organisation) does.
    The real WTF is American English. One would think, with the amount of cash the Federal Reserve are printing right now, you 'merkins could afford to import some spare "U"s and exchange a few "Z"s for "S"s.
  • belzebub (unregistered)

    Oh thanks. I almost forgot there's a way to get a revenge for all those lame stories:

    thedailywtf.com:

    • NoScript -> Forbid google-analytics.com
    • Adblock -> Enable on this site
  • (cs) in reply to belzebub
    belzebub:
    Oh thanks. I almost forgot there's a way to get a revenge for all those lame stories:

    thedailywtf.com:

    • NoScript -> Forbid google-analytics.com
    • Adblock -> Enable on this site

    Why go to that effort, when you could just choose to, you know, not visit the site if it's so lame?

    I'd've thought that anyone who visits the site regularly wouldn't mind supporting its continued existence by ignoring a couple of unobtrusive banner ads as they slag off Hanzo stories in the comments threads... ;)

  • (cs) in reply to JimM
    JimM:
    Steve The Cynic:
    ... There's an XKCD on the topic ...

    "If they say they've solved their problem, NEVER ask how".

    Yup, that's the one.

    Now that my office firewall is after-hours, I found it at http://xkcd.com/763/

  • ¯\(°_o)/¯ I DUNNO LOL (unregistered)

    Wow. Just wow. I think the thing that offends me the most is those enormous if || chains. Holy fuck, lrn2loop. Something like:

    if (match(llelementfirstname, firstnametable))

    where firstnametable is a big JSON array with values to search for and an optional second field for matching llfrmid for the really specific matches. Then all the matching is done in a loop, and all you see in the main code is just essence of what you're trying to match.

    After being being subjected to horribly ugly "example code" related to bringing up a new chip (I do embedded systems programming), I've started to use the term "weeds" to refer to all the garbage that makes code hard to read, including things like "} /* FunctionName */" at the end of functions and short if blocks. If your code wasn't so full of weeds to begin with, you wouldn't need to add those other weeds to make it more "readable"!

    One of my favorite WTFs was code that I had to maintain that was compiled with a specially hacked up GCC 2.95 for ARM (and we didn't even know how it was hacked up help us get away from it). One function had about 50 array elements initialized like "a[1]=0x123; a[2]=0x456; a[3]=0x789; ..." At some point the code generator would get confused and the register allocator would run out of registers trying to compile it. Once I got to be in charge of that code, lots of things went to loops using constant arrays. That bastard version of GCC was a lot happier.

    I take particular pride in things like making initialized array tables where each element fits in one 80-column line of code, with only very simple macro usage (for shrinking commonly repeated stuff like "(void*)" or "|FLAG" in individual elements). Code is so much easier to maintain when it contains as little repeated fluff as possible, by applying the DRY principle to the maximum.

  • anonymous (unregistered) in reply to faoileag
    faoileag:
    No, foo isn't global, foo is just in the same scope as the anonymous function. This is the reason the idiom "var instance = this;" comes in handy when you use anonymous functions in an oo context.
    Honnza:
    the that foo is global is not needed in the example. Even if `callback` is outside `test`, you can do this
    What I should have said is "works IF foo is global OR the anonymous function is in the same scope". The code wasn't a function, so foo WAS global (and it'll always work if foo is global); it also used an anonymous function that was in the same scope as the variable definition, which also works even if the code is inside a function.
    faoileag:
    What's got recursion to do with it?
    Honnza:
    If you want recursion, you can use nested functions, even immediately invoked functions
    I don't necessarily WANT recursion, but I'm forced to use recursion to avoid freezing the GUI (and simple recursion won't avoid this; you have to use setTimeout to give the browser a chance to update). When you have a lot of data to process or a complex problem to solve, and you can either use a recursive or sequential algorithm to do so, the sequential algorithm is often easier to write and it'd be DAMN NICE if you could just stick a sleep() in there so it wouldn't freeze the entire browser while it chugs away at your function.

    Sure, you could also figure out how to write the whole thing as a web worker, but that's as much work as just making a bunch of variables global or passing them as arguments and then making it recursive.

  • foo AKA fooo (unregistered) in reply to faoileag
    faoileag:
    Original code:
    <%set ON = 1%>
    <%set Debugging = 1%>
    if (<%Debugging%> == <%ON%>) {...
    

    Delivered code:

    if (1 == 1) {...

    This is quote common in fact.

    common:
    In fact.

  • foo AKA fooo (unregistered) in reply to ¯\(°_o)/¯ I DUNNO LOL
    ¯\(°_o)/¯ I DUNNO LOL:
    After being being subjected to horribly ugly "example code" related to bringing up a new chip (I do embedded systems programming), I've started to use the term "weeds" to refer to all the garbage that makes code hard to read, including things like "} /* FunctionName */" at the end of functions and short if blocks. If your code wasn't so full of weeds to begin with, you wouldn't need to add those other weeds to make it more "readable"!
    But ... but ... but!

    You know, there may be a 1000 line function somewhere in our codebase, and if we don't, you know, put an ending comment at its end, the programmer needs to, well, SCOLL UP to see the function name (unless the IDE has better support, but anyway). So you see that's why it's so urgently needed. And if we do it once, we need to do it everywhere because, you know, CONSISTENCY! CONSISTENCY! That's important! CONSISTENCY!

    How dare you ... <headasplode> /* end of comment */

  • Sociopath (unregistered)
    TDWTF:
    We here at TDWTF use Google Analytics to see who visits our site
    Ghostery detects the following Reddit tracker widgets when viewing the text of an article:
    Ghostery:
    Detected tracker source URLs: http://www.reddit.com/static/spreddit2.gif http://www.reddit.com/static/spreddit2.gif
    Note that these widgets are part of the page and perform their tracking function even when JavaScript is disabled by something like NoScript.

    After you enable JavaScript on thedailywtf.com, then Ghostery also notes the Google Analytics tracking:

    Ghostery:
    Detected tracker source URLs: http://www.google-analytics.com/ga.js
  • Captain Oblivious (unregistered) in reply to nonpartisan
    nonpartisan:
    You should've seen the original code. It took 60 seconds to analyze a page. That was unacceptable, so Adam tried Google Analytics and it completed the task in only a few milliseconds. Nigel insisted that he could rewrite the code and not be beholden to Google. Now it only takes 20 seconds to analyze a page.

    But it only scans 3000 DOM elements by name. :(

Leave a comment on “A Privacy Monstrosity on Top of a Coding Monstrosity”

Log In or post as a guest

Replying to comment #:

« Return to Article