Sunday 26 November 2017

Spot The Bug: Spacing Out

I'm pleased to bring you yet another edition of Spot The Bug. This one's tiny, so keep your eyes peeled...

Back in action.

Just recently, as part of a programming exercise, I was working on a Password Strength Validator. My idea here was for there to be a text field, and as the user types in a password, there is a label describing the input's password strength as Excellent, Good, Moderate or Weak. For this, I used jQuery to process everything.



It mostly went well. The function I created to determine the password strength did its job and returned the correct values - a password strength indicator (e.g., "Weak") and a more detailed message as to what was wrong with it (i.e, "Password is too short"). The CSS and styling were all fine. I tested it with sample input.

What went wrong

Oh, it looked like everything was wrong. The indicator failed to come on no matter what I typed.



Here's the code. I won't go into detail with the getPasswordStrength() function. Suffice to say, the function worked as expected.
<!DOCTYPE html>
<html>
    <head>
        <title>Password Strength Validator</title>
        <style>
            .password
            {
                display:block;
                width:20em;
            }

            .strength
            {
                font-size:2em;
                font-weight:bold;
                transition:all 1s;
            }

            .comments
            {
                font-size:1em;
            }
        </style>

        <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
        <script>
            function displayPasswordStrength(password)
            {
                if (password.length == 0)
                {
                    $(".indicator.strength").html("");
                    $(".indicator.comments").html("");
                }
                else
                {
                    var pwd_strength = getPasswordStrength(password);
                    $(".indicator.strength").html(pwd_strength.strength);
                    $(".indicator.comments").html(pwd_strength.comments);

                    if (pwd_strength.strength == "Excellent")
                    {
                        $(".indicator.strength").attr("style","color:#00FF00");
                    }

                    if (pwd_strength.strength == "Good")
                    {
                        $(".indicator.strength").attr("style","color:#FFFF00");
                    }

                    if (pwd_strength.strength == "Moderate")
                    {
                        $(".indicator.strength").attr("style","color:#FF4400");
                    }

                    if (pwd_strength.strength == "Weak")
                    {
                        $(".indicator.strength").attr("style","color:#440000");
                    }
                }

            };

            function getPasswordStrength(password)
            {
                ...
            }
        </script>
    </head>
    <body>
        Password:
        <input class="password" oninput="displayPasswordStrength(this.value)">
        <div class="indicator">
            <span class="strength">
               
            </span>
            <span class="comments">
               
            </span>
        </div>
    </body>
</html>


Why it went wrong
As mentioned, the function was working, and firing off upon input. But nothing was being changed on the front-end!

And when I finally found it, I had such a good laugh.
                    $(".indicator .strength").html(pwd_strength.strength);
                    $(".indicator .comments").html(pwd_strength.comments);


This basically means that the element with the class strength within the indicator div was supposed to reflect the strength property of the passwordStrength object returned by the getPasswordStrength() function, and the element with the class comments would display the comments property.

But look closely at the selector on the first line. It was instead looking for an element with both the CSS classes strength and indicator! Same for the next line - looking for an element with both the CSS classes comments and indicator. And came up short.

How I fixed it

I could have just started using ids instead of classes, but really, that would be complicating what was essentially a very simple fix. Just add spaces where they're supposed to go.
<!DOCTYPE html>
<html>
    <head>
        <title>Password Strength Validator</title>
        <style>
            .password
            {
                display:block;
                width:20em;
            }

            .strength
            {
                font-size:2em;
                font-weight:bold;
                transition:all 1s;
            }

            .comments
            {
                font-size:1em;
            }
        </style>

        <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
        <script>
            function displayPasswordStrength(password)
            {
                if (password.length == 0)
                {
                    $(".indicator .strength").html("");
                    $(".indicator .comments").html("");
                }
                else
                {
                    var pwd_strength = getPasswordStrength(password);
                    $(".indicator .strength").html(pwd_strength.strength);
                    $(".indicator .comments").html(pwd_strength.comments);

                    if (pwd_strength.strength == "Excellent")
                    {
                        $(".indicator .strength").attr("style","color:#00FF00");
                    }

                    if (pwd_strength.strength == "Good")
                    {
                        $(".indicator .strength").attr("style","color:#FFFF00");
                    }

                    if (pwd_strength.strength == "Moderate")
                    {
                        $(".indicator .strength").attr("style","color:#FF4400");
                    }

                    if (pwd_strength.strength == "Weak")
                    {
                        $(".indicator .strength").attr("style","color:#440000");
                    }
                }

            };

            function getPasswordStrength(password)
            {
                ...
            }
        </script>
    </head>
    <body>
        Password:
        <input class="password" oninput="displayPasswordStrength(this.value)">
        <div class="indicator">
            <span class="strength">
               
            </span>
            <span class="comments">
               
            </span>
        </div>
    </body>
</html>


Now it works!


Moral of the Story

jQuery is really neat and all, and selectors are easy to use. And also easy to get wrong if you're an idiot like me. This was not a syntax error, maybe not even a logic one. It was pretty much a typo. Oh, the horror. See how even a space can ruin your day?

Looks like another bug squashed. Excellent!
T___T

Wednesday 22 November 2017

Film Review: The Girl With The Dragon Tattoo (2011) (Part 2/2)

As with any remake, comparisons with the original are inevitable. The 2011 remake of The Girl With The Dragon Tattoo finds itself in the unenviable position of being compared to both the 2009 version and the novel. In my review, there were far more things that I mentioned liking than not liking; however, that's mostly because the things I didn't like were a result of unfavorable comparisons with the 2009 version, which I'm saving for this part.

Characters


2009
2011

Noomi Rapace's Lisbeth Salander (2009) vs Rooney Mara's Lisbeth Salander (2011) - this one is a very close call, and it's extremely hard for me to pick a clear winner between the two. That's because while these two fine actresses bring forth markedly different Lisbeths, they're both Lisbeth. Albeit different aspects of Lisbeth that can be inferred from the novel. Noomi Rapace portrays the hard-as-nails Lisbeth Salander who will fuck you up if you cross her. There is no question at all, that should you accost her and fail to kill her, whose ass is going to be thoroughly kicked. It radiates through every pore of the actress. Rooney Mara's Salander, on the other hand, exudes the other side of Salander - the antisocial, awkward and emotionally stunted persona is played up, noticeably more so than the awesome capacity for ass-kicking. It's a testament to the complexity of the character written by the late Stieg Larsson that two different people could conceivably portray her so convincingly.

Who looks more the part? Well, from the neck up, Mara is pale as a ghost and Rapace has this psycho glare going on. Both are thin - Mara more so, Rapace more athletic. So far so good. Mara, however, has significantly larger boobs than Rapace, whose chest really mirrors the description of Lisbeth Salander having a boyish figure. Plus, the unshaven pits which pretty much hammer home the "antisocial monster" vibe. I think Rapace kind of wins here, at least in the body double department. She's uncomfortable to look at.

2009
2011
Michael Nyqvists's Mikael Blomkvist (2009) vs Daniel Craig's Mikael Blomkvist (2011) - there's no contest here. Michael Nyqvist is significantly older, chubbier and hairer than Daniel Craig in the movie. Just look at Craig's glorious naked torso and tell me that belongs to a journalist that has been described to be battling the middle-age bulge. That aside, Craig just isn't right for the role. Not even considering that Nyqvist got there first and did such a spectacular job that filling his shoes would be nigh impossible. Michael Nyqvist's Blomkvist is one that the average sedentary moviegoer can identify with - not the rugged good looks, chiselled torso and superspy coolness of Daniel Craig.

I mean, not once during the entire scene where Martin Vanger tortures and almost kills Mikael Blomkvist, could I believe that this guy was in danger of getting killed. Come on, that's Daniel Craig!

Craig is also a lot more animated with his movements, what with the squinting, head motions and hand gestures. Nyqvist used his face. His eyes.


2009
2011



Peter Andersson's Nils Bjurman (2009) vs Yorick van Wageningen's Nils Bjurman (2011) - Peter Andersson is far older, creepier and predatory than Yorick van Wageningen in this role, who musters a sleazy vibe at best. The 2009 Nils Bjurman's rape of Lisbeth was played with significantly more violence (though both on-screen rapes are just as horrific).

2009
2011
Peter Haber's Martin Vanger (2009) vs Stellan Skarsgård's Martin Vanger (2011) - Peter Haber did a fine job. That said, Stellan Skarsgård beats him hands-down with his portrayal. Skarsgår's Martin Vanger positively screams snake near the end.

2009
2011



Lena Endre's Erika Berger (2009) vs Robin Wright's Erika Berger (2011) - I think both actresses are pretty competent in their own way and could look like an Erika Berger. Unfortunately, they're given so little to do in this movie that Erika's awesomeness in the novel just doesn't translate very well here. A limp stalemate.

2009
2011
Tomas Köhler's Plague (2009) vs Tony Way's Plague (2011) - Tomas Köhler's Plague shared an acerbic camaraderie with Lisbeth Salander in the Swedish version. Tony Way's Plague just comes off as a dick, and lacks the presence that made Tomas Köhler's Plague stand out.

Story

Certain story elements are more in line with the novel's, and some are simply done better - more well-executed, more value in their inclusion.


2009
2011
First off, the techy bits in the 2009 version come across as a little too retro in comparison with the 2011 version. Look at the font, for instance!  The 2011 version doesn't go over the top showcasing Lisbeth's hacking skills, and still shows a reasonable UI. To be fair, I think it's more the sign of the times. The 2009 version wasn't released in an age where Google, Facebook and YouTube had become that mainstream.

2009
2011
How Lisbeth's laptop gets damaged. In the novel, it cracks when a car backs up over it, which is, well, boring. The 2009 version shows us that it got damaged when Lisbeth gets attacked by a bunch of guys in the subway, whom she fights off like an enraged badger, using a broken bottle. The 2011 version shows us that a snatch thief grabs Lisbeth's bag (again, in the subway), and in the ensuing tussle on the escalator (where she naturally kicks his ass), it gets damaged. And Lisbeth just coolly glides down the escalator later. Both are suitable plot points leading to the death of that laptop and showing us Lisbeth's aggression. The 2009 version feels more visceral and Lisbeth takes more lumps in this one. The 2011 is just a little too neatly done. Too slick.

2009
2011

Bjurman coercing our super hacker Lisbeth into blowing him. I have to give the prize to the 2009 version here. It was more drawn out and the overall result was more creepy. The 2011 version just felt... sleazy. Also, this might be a minor point here, but I prefer the 2009 version's take of Lisbeth washing her mouth later. She actually sticks her fingers down her mouth and scrubs!

Rape scenes. Both 2009 and 2011 versions depicted the horrific rape of Lisbeth Salander at the hands of Bjurman quite ably. Though I must say the 2009 version felt way more violent, mainly because Bjurman actually smacked Lisbeth around first.

Bible clues. In the novel, Mikael is stumped by the names and numbers on the list until his daughter Pernilla points out that they were taken from the bible. The 2011 version stays true to this, while the 2009 opts to cut out Pernilla as a character and have Lisbeth deliver the message. Both work well, I guess, though bonus points to the 2011 version for including this detail.

Sex scenes between Mikael and Lisbeth. In the 2009 version, Mikael is dumbfounded when Lisbeth expresses a desire to have sex with him out of nowhere. After doing it, Lisbeth refuses to cuddle. Her coldness is totally in character here. In the 2011 version, Mikael and her do it with vigor, and the scene fades to black with no mention of it later. Later on, Lisbeth sternly tells Mikael to put his hand back under her shirt, and they end up having sex again. This didn't really ring true for me. Also, in the 2009 version, Mikael and Lisbeth's naked bodies aren't exactly conventionally beautiful. The sex feels more real. In the 2011 version, Lisbeth has great skin and nice tits and ass, and Mikael has one hell of a sculpted body. This just forcefully reminded me that I was watching a Hollywood remake.

Reunion of Harriet and Henrik Vanger. The 2009 version's reunion was touching in all its emotional honesty. The 2011 version felt a little... rushed.

Cinematography

The 2011 version boasts very nice camera angles and majestic landscapes. In these areas, it stands out significantly next to its comparatively drab-looking predecessor. The sets, in particular, are markedly different.

2009
2011

Milton Security (2009) vs Milton Security (2011) - There's not much to choose between these iconic scenes where Dirch Frode and Dragan Armansky speak with Lisbeth in the Milton Security conference room. The 2009 version of the office is more warm, while the 2011 version is more sterile. One interesting thing I noted in the 2011 version is that there's hardly a shot of all three of them in frame at one time. Either Lisbeth has her back to us and is out of focus, or Dirch and Dragan are. Wonder why.

2009
2011

The Millennium (2009) vs The Millennium (2011) - The 2009 version of The Millennium's office had a cosy homely feel to it. The 2011 plays this up even more, but somehow it just feels too clean.

2009
2011

Plague's apartment (2009) vs Plague's apartment (2011) - The 2009 version is dark, smoky and dank, like some kind of lair. With a greenish tinge, even! The 2011 is a tad more spacious. Doesn't really carry the vibe.

2009
2011

Martin Vanger's basement (2009) vs Martin Vanger's basement (2011) - both versions are remarkably clean and bright. A great deal of thought seems to have been put into them. We see the cages, the torture instruments, the apparatus used to suspend Mikael, and so on. Both are great, and I can't reasonably choose a winner here.


Conclusion

The American remake is a remarkably polished effort. It's certainly more stylish than its predecessor. And that's all it really has going for it. Story-wise, it offers nothing really new. Rooney Mara's new take on Lisbeth Salander was interesting, and Stellan Skarsgård stood out as Martin Vanger. The rest of the acting was... meh. Still, brave and commendable effort, I suppose. Though "outstanding" might be a bit much.

Personally? I prefer the Swedish version. It did way more for me, raw as it might have felt sometimes. Of course, seeing as I've seen more of the 2009 version, including its sequels, I may be biased here.

The remake doesn't suck! It's a Mara-cle!
T___T

Sunday 19 November 2017

Film Review: The Girl With The Dragon Tattoo (2011) (Part 1/2)

Earlier this year, I provided a film review of The Girl With The Dragon Tattoo. Today will be more of the same, only it's a review of the American remake, released in 2011. Now, the thing about Hollywood remakes of foreign films is that they usually have better production values, but little else. We'll take a look at this film, and its 2009 incarnation, and compare them side by side.

Warning - nudity, violence

As with its predecessor, this film doesn't shy away with portraying sex  and violence; particularly violence towards women which is arguably the crux of the story. Does it, however, offer anything new? Let's find out.

I don't own any of the screenshots.


The American remake of The Girl With The Dragon Tattoo is not too hard to watch, though if you've watched the 2009 version and/or read the novel, you might be inclined to be critical.

The Premise

Refer to the last review of this film and the review of the novel. Almost word for word, the storyline is the same. There are certain places where the script for this movie more closely matches the novel, than the Swedish version's take.

The Characters

Daniel Craig, star of the James Bond movies, is the journalist Mikael Blomkvist. Intense gazes notwithstanding, he doesn't strike me as a Blomkvist. I'm thinking the producers chose poorly for this role.

Rooney Mara as the computer hacker Lisbeth Salander. Recently saw her in Pan. She's cold and aloof, as might be expected, but she's also emotionally vulnerable and somehow fragile. This is in stark contrast to the scenes where she lets loose, and this somehow makes it even more terrifying.

Christopher Plummer plays Henrik Vanger. He reminds me a little of Sir Ian McKellan as Magneto. Way more energetic than I'd have expected from a character like Henrik Vanger, but no less shrewd.

Yorick van Wageningen tries not to ham it up as the creepy and despicable Nils Bjurman... and just barely succeeds. The result is a rather wimpy Bjurman, though the rape and torture scenes are no less brutal for it.

Stellan Skarsgård is Martin Vanger. I last saw the guy in the Exorcist: The Beginning and Thor, and damn he is superb here. Just affable enough to seem harmless but shrewd enough to run a company. And when he finally reveals his true colors, you'll see a performance you won't forget. Mesmerizing as a snake, and totally pleasant even as he's explaining just how close you are to being murdered in cold blood. He also happens to be the only Swedish actor among the main cast.

Steven Berkoff as Dirch Frode. It's a very one-note performance here and xxx does not look really comfortable in the role. Half the time he looks constipated.

Robin Wright as Erika Berger. I like watching Robin Wright, but here she manages to be even more inconsequential than the last Erika Berger, played by Lena Endre.

Tony Way is Plague, Lisbeth's computer geek associate and occasional partner-in-crime. His brief portrayal didn't do it for me. Could be due to a very limited script, but the interaction with Lisbeth felt off.

Geraldine James as Cecelia Vanger. Pretty, but nothing noteworthy here. Colder and more brusque than the 2009 incarnation.

Joely Richardson makes a late but welcome appearance as Harriet Vanger. I wondered where I'd seen this face before, and was flabbergasted to realize it was in one of my all-time favorite flicks The Patriot, where she was this hot bodacious babe in a sinfully tight Victorian dress. Holy shit, that was eighteen years ago!

Josefin Asplund plays Mikael's daughter Pernilla. Typical teenager fare here, but she serves as an important plot device.

Goran Višnjić is Dragan Armansky. We only see him in a few scenes and the actor has very little to do other than put on an authoritative air as boss of Milton Security. A thankless role.

Élodie Yung as Lisbeth's on-off lover Miriam Wu. I've seen her in Gods of Egypt last year, The Hitman's Bodyguard this year and more recently, in the Daredevil and The Defenders series as Elektra. She actually went topless for this bit part, so it must have been one of her earlier roles.

Bengt C.W. Carlsson as Palmer Holmgren. Mostly a non-speaking (and almost non-moving) role, due to the character suffering a stroke.

The Mood

Cold and dark. Literally, because a large part of the movie takes pace in winter. Most of the scenery is really pretty, what with the snowbound landscapes and all. And the use of music and cut-scenes to ratchet up the tension when it's warranted... top-class.

What I liked



The opening credits. So creepy. A melting-pot of morphy special effects. And that music.

Lisbeth stands by casually as a woman enters the 4-digit passcode to a secured apartment building, and just seconds later, produces the same passcode by sound alone. Nothing's safe from this hacker.


In some ways, the 2011 remake is more thorough with the details. They even included the cat that was mutilated!

This fight scene between Lisbeth and a would-be snatch thief on the escalator in a subway. Not so much the slick action, but here we see Lisbeth unleash her frustration, and it is terrifying.


This close-up shot of the cheque Bjurman cuts Lisbeth after raping her. Somehow it just slams the message home so much more brutally than the obligatory post-rape shower scene.


This shot of Lisbeth hacking into Wennerström's email made me laugh out loud.


"Do you doubt anything I've said? Do you doubt what's in the reports that have followed me around all my life? What do they say? If you had to sum it up, they say I'm insane. No, it's OK, you can nod because it's true. I am insane."

Holy crap, Rooney Mara delivers this in the most chilling manner ever.


This t-shirt Lisbeth is wearing during the classic scene where she and Mikael finally meet.


I really, really enjoyed the torture scene near the end. Martin Vanger even has some ridiculously upbeat music playing as he's planning to gut Mikael like a fish.

What I didn't

Generally, the entire film still boasted the same Swedish names and locations in the book - but everything was said in English. Which is pretty jarring.


The words tattooed by Lisbeth on Bjurman are in English, and the message has been truncated from the novel. I guess it's one of those little tradeoffs you have to make when you're trying to do an American remake of a Swedish original.

The sex scene between Lisbeth and Mikael felt even more abrupt and forced than it did in the film's predecessor. Nice angles, though.

The rest of the film isn't compelling enough to watch. After the entire Martin Vanger sequence, putting Lisbeth through the motions of outing Wennerström is faithful to the novel, but really very anti-climatic.

Conclusion

The 2011 remake is a decent piece of film-making, but unfortunately it will always be compared against the merits of its predecessor. And safe to say, there are plenty of instances where it falls short. Still, it's a slickly produced piece of film and does justice to the novel. Lisbeth Salander will probably be one of the roles Rooney Mara is forever remembered for.

My Rating

6.5 / 10

Next

A comparison of the 2009 version and this one. Which one comes out ahead, and in what areas?

Friday 10 November 2017

Web Tutorial: Ruby Mad Libs

Hey, y'all.

Ever heard of this game called Mad Libs? You supply a list of words and the players make a story out of them. Most of the time, the results are so whacky, it's funny.

If you enjoyed playing that, you're in luck because we're going to make our very own Mad Libs game. For that, we'll be using Ruby. QBasic will do, too, in a pinch, but Ruby makes it easier by having hash features and string substitution similar to C. So if you've got Ruby installed, create your program file and let's get cracking!

First, we do this. As you may have surmised, this prints a nice introductory text on the screen.
puts "Welcome to TeochewThunder's Mad Libs!"


Next, we're going to introduce a Do-While loop. In Ruby, it's expressed as such. Here, we have a variable, continue, which is set to an empty string. And the program continues for eternity until a certain condition is met. In this case, that's when continue has a value of "Y" or "y". Y, you ask? (heh heh) Well, read on...
puts "Welcome to TeochewThunder's Mad Libs!"

continue = ""
begin

end while continue == "Y" or continue == "y"


Because, within the loop, we print a string asking if the user wishes to continue, then use a gets statement to assign user input to the variable continue. So if the user enters anything else but "Y" or "y", the program ends.
puts "Welcome to TeochewThunder's Mad Libs!"

continue = ""
begin
    puts "Do you wish to continue? (Y/N)"
    continue = gets
end while continue == "Y" or continue == "y"


Try it. Does it work? I bet the program exits no matter what!


That's because if you typed in "Y" or "y" as input and then pressed the Enter key, the input gets captured as "Y\n" or "y\n". Yes, even the Enter key counts as input! Seems silly, doesn't it? But fret not, there's an easy way out. Just chomp the end off, and your input will be correct.
begin
    puts "Do you wish to continue? (Y/N)"
    continue = gets.chomp
end while continue == "Y" or continue == "y"


Try it again. "Y" or "y" should cause the program to keep running!


Now, within the loop, let's set the variable content by calling a function, getMadLibContent()... and create that function right at the beginning of your code.
def getMadLibContent()

end

puts "Welcome to TeochewThunder's Mad Libs!"

continue = ""
begin
    content = getMadLibContent()

    puts "Do you wish to continue? (Y/N)"
    continue = gets.chomp
end while continue == "Y" or continue == "y"


This function should return a hash object. First, let's define an array, contentTypes.
def getMadLibContent()
    contentTypes = [ ]
end


Each array element is a hash object, containing they key story, which points to a string, and words, which points to another array.
def getMadLibContent()
    contentTypes = [
            {
                "story" => "",
                "words" => [ ]
            },
    ]
end


Here, we define the story, using "%s" where we expect words to be substituted.
def getMadLibContent()
    contentTypes = [
            {
                "story" => "While eating %s, I %s took up my %s and placed it under my %s. It %s %s.",
                "words" => [ ]
            },
    ]
end


Next, we make an array of the kind of words we want to substitute into the placeholders provided by "%s". Bear in mind that they have to be in order.
def getMadLibContent()
    contentTypes = [
            {
                "story" => "While eating %s, I %s took up my %s and placed it under my %s. It %s %s.",
                "words" => [
                    "food (e.g, pie, noodles, shortcake)",
                    "adverb (e.g, happily, carefully, quickly)",
                    "noun (e.g, hammer, balloon, cigar)",
                    "item of clothing (e.g, hat, shoe, coat)",
                    "past action (e.g, shouted, ran, floated)",
                    "adverb (e.g, happily, carefully, quickly)"
                ]
            },
    ]
end


Make two more! Get creative!
def getMadLibContent()
    contentTypes = [
            {
                "story" => "While eating %s, I %s took up my %s and placed it under my %s. It %s %s.",
                "words" => [
                    "food (e.g, pie, noodles, shortcake)",
                    "adverb (e.g, happily, carefully, quickly)",
                    "noun (e.g, hammer, balloon, cigar)",
                    "item of clothing (e.g, hat, shoe, coat)",
                    "past action (e.g, shouted, ran, floated)",
                    "adverb (e.g, happily, carefully, quickly)"
                ]
            },
            {
                "story" => "She bought a %s %s and started %s it as it %s. It felt %s to do so, and she continued %s.",
                "words" => [
                    "descriptive (e.g, blue, glad, large)",
                    "furniture (e.g, table, stool, cupboard)",
                    "active action (e.g, running, eating, fighting)",
                    "past action (e.g, shouted, ran, floated)",
                    "descriptive (e.g, blue, glad, large)",
                    "active action (e.g, running, eating, fighting)"
                ]   
            },
            {
                "story" => "His %s was a %s %s and %s %s like a %s. He would try to %s, but this would result in %s %s.",
                "words" => [
                    "relative (e.g, father, son, cousin)",
                    "descriptive (e.g, blue, glad, large)",
                    "noun (e.g, hammer, balloon, cigar)",
                    "adverb (e.g, happily, carefully, quickly)",
                    "past action (e.g, shouted, ran, floated)",
                    "animal (e.g, goldfish, mouse, lion)",
                    "action (e.g, think, stand, kick)",
                    "people (e.g, men, gardeners, mechanics)",
                    "active action (e.g, running, eating, fighting)"
                ]   
            },
    ]
end


OK, that's enough content to start with. You want there to be an element of surprise, so generate a random number and assign the value to the variable scenario, using the rand() function and passing in the length of the contentTypes array as an argument, which is 3. This will net you a random number from 0 to 2. Then create a variable, madlibcontent, and set it to the value of the array element in contentTypes pointed to by scenario. You don't have to explicitly type a return statement at this point, because Ruby functions automatically return the last expression in the function.
def getMadLibContent()
    contentTypes = [
            {
                "story" => "While eating %s, I %s took up my %s and placed it under my %s. It %s %s.",
                "words" => [
                    "food (e.g, pie, noodles, shortcake)",
                    "adverb (e.g, happily, carefully, quickly)",
                    "noun (e.g, hammer, balloon, cigar)",
                    "item of clothing (e.g, hat, shoe, coat)",
                    "past action (e.g, shouted, ran, floated)",
                    "adverb (e.g, happily, carefully, quickly)"
                ]
            },
            {
                "story" => "She bought a %s %s and started %s it as it %s. It felt %s to do so, and she continued %s.",
                "words" => [
                    "descriptive (e.g, blue, glad, large)",
                    "furniture (e.g, table, stool, cupboard)",
                    "active action (e.g, running, eating, fighting)",
                    "past action (e.g, shouted, ran, floated)",
                    "descriptive (e.g, blue, glad, large)",
                    "active action (e.g, running, eating, fighting)"
                ]   
            },
            {
                "story" => "His %s was a %s %s and %s %s like a %s. He would try to %s, but this would result in %s %s.",
                "words" => [
                    "relative (e.g, father, son, cousin)",
                    "descriptive (e.g, blue, glad, large)",
                    "noun (e.g, hammer, balloon, cigar)",
                    "adverb (e.g, happily, carefully, quickly)",
                    "past action (e.g, shouted, ran, floated)",
                    "animal (e.g, goldfish, mouse, lion)",
                    "action (e.g, think, stand, kick)",
                    "people (e.g, men, gardeners, mechanics)",
                    "active action (e.g, running, eating, fighting)"
                ]   
            },
    ]

    scenario = rand(contentTypes.length)
    madlibcontent = contentTypes[scenario]
end


Now, in your loop, content should be the hash object you got from the function getMadLibContent(). Create a variable, userProvided and set it to store an array that has the same length as the words array in the content hash object.
continue = ""
begin
    content = getMadLibContent()
    userProvided = Array.new(content['words'].length)

    puts "Do you wish to continue? (Y/N)"
    continue = gets.chomp
end while continue == "Y" or continue == "y"


Then iterate through the words array using a For loop.
continue = ""
begin
    content = getMadLibContent()
    userProvided = Array.new(content['words'].length)
    for i in 0..content['words'].length-1

    end

    puts "Do you wish to continue? (Y/N)"
    continue = gets.chomp
end while continue == "Y" or continue == "y"


In the For loop, print a statement asking the user to enter a word or phrase, then print the clue provided by the appropriate element in the words array. And obtain user input using gets again. Don't forget to chomp! Assign the input to the corresponding element in the userProvided array.
continue = ""
begin
    content = getMadLibContent()
    userProvided = Array.new(content['words'].length)
    for i in 0..content['words'].length-1
        puts "Please enter a word or phrase:"
        puts content['words'][i]

        userProvided[i] = gets.chomp   
    end

    puts "Do you wish to continue? (Y/N)"
    continue = gets.chomp
end while continue == "Y" or continue == "y"


So far so good, yeah?


Now it's time to tell the story! Use the puts statement to print out the story string from the content hash object.
continue = ""
begin
    content = getMadLibContent()
    userProvided = Array.new(content['words'].length)
    for i in 0..content['words'].length-1
        puts "Please enter a word or phrase:"
        puts content['words'][i]

        userProvided[i] = gets.chomp   
    end

    puts "Here is your story:"
    puts content['story']

    puts "Do you wish to continue? (Y/N)"
    continue = gets.chomp
end while continue == "Y" or continue == "y"


Try it! Oh dear, not really what you wanted!


Use this statement instead, followed by a "%" and a test array.
puts content['story'] % ["test1","test2"]


See? You get an error because there are more instances of "%s" than there are elements in the array you provided. But how would we know how many instances of "%s" to replace, and what to replace them with?


Use the userProvided array instead. This will substitute all instances of "%s" with the appropriate element from the userProvided array!
puts content['story'] % userProvided


Try it again. There's your story!




This is really just a simple programming exercise that I'm using as an initial foray into Ruby. I'm really digging it so far.

I'll leave you to %s your %s. Have %s fun!
T___T

Sunday 5 November 2017

Ruminations of a 40-year old Geek

Lordy, Lordy, look who's forty!

Yep, that one was plagiarized from Silicon Valley Season 4, but it seems particularly apt.

His Teochewness turns 40 today, and would like to expound on a very pertinent topic in the tech industry - aging. Or rather, aging developers. If I told you I didn't feel the effects, that would be a big fat lie. I didn't become an old fart overnight - these effects have been creeping up over the past few years.

Overall Health

For the longest time since 2008, I had not been taking sick leave. I'd been running on a heady mixture of sunlight, cigarettes and Teochew arrogance. That record was broken last year, and this year. That's two times in two years after a period of eight years. The illusion that I'm made of iron is long gone, and I feel just as fragile as every other schmuck on this planet.

My joints are stiff. My teeth feel weak. If I sit too long, my legs fall asleep and my back and neck start to whine. My cholesterol level is ambitiously scaling new heights, and my digestive system just isn't what it used to be. Come to think of it, my appetite isn't what it used to be. Buffets? Forget it, sunshine.

And I'm not even going to go into detail about the severe discomfort that occurs whenever it gets cold.

Yeah bro,
it's like that.

On the bright side, I look pretty good without my clothes on. Pretty good for a 40-year-old, that is. This ain't no Manhunt torso, but damn if it isn't finer than what the average 30-year-old has to offer. Too bad looking good is just about the only thing this aging body does well these days. Seriously, what's the point of having abs if your stomach can't digest the sinfully greasy and spicy stuff without complaining? Or having nicely toned legs if your goddamn knees creak every time you walk too fast?

Oh, you think I might be exaggerating just a wee bit? We'll talk again when you turn 40.


Fatigue

Another thing about getting to this age, is decreasing energy levels. I get tired a lot more easily than I used to, and it shows. And with this development, changes to the lifestyle are in order.

Energy levels: down.

No more late nights out. You want to spent all night drinking beer and reminiscing? Sorry buddy, you're out of luck. Don't call after 10pm, I ain't picking up. Even an wrinkled old bastard like me needs his beauty sleep.

Vastly reduced overtime in the office. I get my shit done, and leave. Around 6pm, my concentration drops off noticeably and it's all I can do to keep my eyes open. That's a stark contrast to five years ago, when I was still pulling twelve-hour workdays and getting in the office on weekends and public holidays. Now if I stay back and keep working past 7pm, the first thing I'm gonna be doing next morning is undoing all the shit code I wrote last evening. That helps no one.

No more outside projects. These used to be ways to supplement my miserable income, but lately I've been declining all offers. While anti-moonlighting clauses are a staple in almost all employment contracts, they're almost impossible to enforce with freelance projects. But freelance projects take - you guessed it - energy. Energy I don't have. The fact that my income is no longer miserable (maybe even excessive now) doesn't hurt.

And especially - no more losing my temper. Sure, I still get annoyed from time to time. But explosive bursts of angst are a thing of the past now. People say this is due to maturity. A sign of me staying above it all.

If only.

No, this is due to a dwindling supply of energy, and when you're dealing with a limited supply of anything, you tend to want to make it count. That means no more unproductive energy-sapping activities like flame wars, Internet arguments or even offline arguments. It's not even like reacting to some idiot on Social Media would make me feel tired - just thinking about reacting to some idiot on Social Media already makes me feel tired. These days, I'm more than likely to simply agree just so the other party can shut up. Hey, so somebody stays ignorant. So be it. Ain't my job to educate the world. Life's short, and for people like me, it just got a whole lot shorter.

Dude, I'm 40 and statistically, I have another 20 years left, 30 if I'm lucky. If you think I'm going to waste any of it on a pissing contest with some pimply teenage wanker on Social Media, think again.

Attitude

There was a time I felt driven to prove my worth as a professional web developer. Those days are over. It's not so much complacency; instead, it's more about acceptance. I accept that I'm not some hotshot that can walk into any tech firm and instantly land a job. In fact, I'm probably not even in the bottom 25 percentile of tech minds on this island. This isn't humility, either. Again, it's acceptance.

I'm also a lot more zen about underachieving these days. Succeed or fail, life goes on. And if you disagree, feel free to shoot yourself in the head next time you fall short. I'll help document your dramatic gesture on YouTube.


You failed? Die, loser.

Try not giving a shit. It's surprisingly empowering. People are vain, hypocritical, and put a ridiculous amount of effort into projecting some kind of image to the world. This 40-year old dev has neither the time nor the inclination. Being insecure makes you open to manipulation. Fuck all of that.

Surprisingly, though, there are some things I've come to care about more, instead of less. Aging could be making me less gung-ho... or I could be mellowing. What a scary thought. At work, I'm seeing thirtysomethings just as aggressive and driven as I was years ago. And unfortunately, just as stupid about it.

Where I once only cared about getting shit done come hell or high water, getting shit done right has come to matter just as much, if not more. "But it works!" is the layperson's excuse. Guess what - I no longer work for laypeople and therefore, no longer have the luxury of that excuse. Any idiot can write working code - now I have to hold myself to higher standards.

Where I once saw office punctuality as a crutch for people who don't have anything meaningful to contribute, I now see it as a mark of reliability - as in, people can generally count on you to be available in the office by 9pm, not a minute later. Being on time now matters more than staying back in the office or working on weekends. Being reliable has become more important than being the superstar workhorse.

Where I once prided myself on the number of different languages and platforms I've done stuff in, I've come to value team skills more. Communication, usage of code repositories, writing clean readable code. I'm no longer that 30 year old cowboy cop developer, but rather, part of a unit. Besides, very few companies need a developer who's coded in ten different languages - but every company likes their devs to be good at communication and teamwork.



In a wrinkled nutshell (God, that sounds gross)

There's so much you lose as you age. Thankfully, hanging out with younger people helps realize how much I've gained, and hanging out with older people have helped me realized how much I've still got going for me. Perspective - it's underrated.

Many senior regards,
T___T