Saturday, 8 September 2018

Online Lynch Mob Activated!

It's all over the Internet and Social Media. A group of five - historian PJ Thum, activists Jolovan Wham and Kirsten Han, cartoonist Sonny Liew and former Singapore citizen Tan Wah Piow - headed out to meet Tun Dr Mahathir bin Mohamad, Prime Minister of Malaysia, for a chat about democracy, gay rights and all that jazz. PJ Thum posted a photo of him and Dr M on Facebook, urging him to "take leadership in South-east Asia for the promotion of democracy, human rights, freedom of expression and freedom of information". Considering Dr M's unfriendly attitude towards Singapore, both past and present, this looked suspiciously like a middle finger from Thum cast in the general direction of Singapore's ruling party, the People's Action Party (PAP).

The photo in question.

PAP MP Mr Seah Kian Peng responded with an insinuation that Thum harbored ill intentions for Singapore, and threw some shade about why the other two (Jolovan Wham and Kirsten Han) were associating with such a malcontent. Within a day, the Internet was up in arms with cries of "treason" echoing through Facebook. And from there, things started getting messy. Instead of shutting the hell up like a good boy, Jolovan Wham chose to double down with this decidedly defiant response.

The thing is, treason involves heinous acts like selling state secrets or helping outsiders to overthrow the Government... things that none of them are in any position to do even if that had been their intent. And if one wishes to argue that their intent was treasonous, I'm pretty sure openly committing treason and posting the evidence on Facebook goes against all conventional logic.

Now, all of this is Singapore politics. Ill-advised as I think the antics of the five were, this is a tech blog and I'll leave dissection of their actions to more political minds. What I would like to focus on, are the actions of Mr Seah Kian Peng in this entire debacle. Because this concerns the Internet, and all the riff-raff that go with it. I speak today, not as a fanboy of either side (I'm far too busy being awesome to be any kind of fanboy, period) but as a concerned citizen. And as a web developer, surprise, surprise, I happen to know a thing or two about the Internet.

When Mr Seah accused Thum  - and Kirsten Han and Jolovan Wham by association - of harboring ill intentions, people jumped on the bandwagon. There were cyber screams of righteous outrage, a great deal of chest-thumping, name-calling and accusations of treason (yes, there's that word again), capital punishment and stripping of citizenship. Kirsten Han reported that death threats had been made against her and Jolovan Wham. Mr Seah then put up a statement.

"Whilst we have different points of views, I call on all to maintain a certain decorum in our comments and we should not get personal or abusive. We can all agree to disagree and be civil about it. It is regretful that I see all kinds of abusive remarks that are made by many different individuals (and trolls) against each other. I do not support such types of comments, regardless of what views or positions they take."

On the surface, it was a nice gesture. Gentlemanly speech. Hit all the right notes and even managed to sound sincere. Unfortunately, it was a case of too little, too late. It amounted to a mild admonishment, coupled with an attempt to distance himself from the extremists among the PAP fan club. The damage had been done. He had stirred up an online lynch mob which was baying for blood, and now that he had publicly distanced himself from the unpleasantness, this gave them carte blanche to do as they pleased without fear of implicating the PAP. Arguably, it made things worse, not better.

A mob.

OK, maybe that's just a wee bit too cynical. I'm going to give Mr Seah the benefit of the doubt and assume he wasn't doing this deliberately. The situation simply got away from him. That would be adequate mitigation in most cases... except that Mr Seah is both a Member of Parliament and member of the Select Committee on Deliberate Online Falsehoods, a position which, one might say, requires a certain amount of savvy with the Internet. And that makes this entire situation unacceptable. As a public figure, one has to take responsibility for the impact of his words uttered in public, especially when these words stir up such furor.

It's not enough to say he didn't know better, because a man in his position should know better.

Instead of merely saying he did "not support such types of comments", I submit that he should have gone a step further and warned his audience that he neither condones nor tolerates Hate Speech, and that such would be investigated by the police regardless of whose side they're on. Because, you know, some people are awfully brave when they think there are no consequences for their words.

Final Thoughts

To be clear, I'm not worried about the clowns who are screaming self-aggrandizing rubbish like "if I was there, I would punch that traitor's face". All this is hot air and faux-patriotic bluster, nothing more. This is Singapore, and as much as I love her, she's filled with chickenshit keyboard warriors who talk a good game behind a computer screen but totally lose their nerve when their bluff is called.

No, I'm more concerned about the ones who are getting quietly stirred up. You'll never see them coming.


Remember Amos Yee in 2015? There was some loser who came out of nowhere and slapped Amos Yee while he was exiting the courtroom. He didn't post on Facebook and say "I'm gonna slap that punk". No, he just came right out and did it. Substitute "slap" with something more violent, like "stab", and Amos Yee's name with any of the three currently under fire - PJ Thum, Kirsten Han or Jolovan Wham - and you see how we might have a problem.

Is Mr Seah going to take responsibility for something like this? Someone has to. Like it or not, this is 2018, and this is the Internet. If this gets out of hand, perhaps we need more capable hands.

You see, I have shockingly low moral standards for leaders of my country. They don't have to be of sterling character - they can be utterly annoying, perverts or even ruthless bastards. But what I cannot - will not - condone, is incompetence. That's a hard, non-negotiable line. And if this was a misstep by Mr Seah, it's not quite gross incompetence, but it's close. On the other hand, if Mr Seah had engineered and intended this outcome, I can only say - congratulations and well-played, Sir. I approve.

That's all from me. Heading out for lynch... I mean, lunch!
T___T

Wednesday, 5 September 2018

Five Examples of Terribly Useless Commit Remarks

The ability to work in a team is an oft-understated part of a developer's skillset. Sure, being able to write good working code is always well-received. But being able to collaborate with others is one of the major things a developer is judged on.

Committing changesets to a code repository is one of the ways a developer collaborates with others. And to do that well, at the very minimum, one needs to understand the art of writing useful commit remarks. That's a subject worth investing some time in to study, but for today, let's examine some of the most God-awful useless commit remarks I've ever had the misfortune of encountering. I've categorized them into five groups, not necessarily in order of futility.

1. The Mysterious

Invisible.

Changeset By Time Remarks
11332667 Ms Mysterious 31 July 2018, 15:03:14 Details
11332668 Ms Mysterious 31 July 2018, 15:35:24 Details
11332669 Ms Mysterious 31 July 2018, 16:12:11 Details

Do you see the problem with the commit remarks? No? That's because there are no remarks. Meaning, we have no clue what the commit was for and actually have to delve into the code to make sense of of the why and what.

2. The Nonsensical

Crazy randomness

Changeset By Time Remarks
98090 Nonsensical Jr. 18 August 2018, 09:39:16 Details xyz
98091 Nonsensical Jr. 18 August 2018, 09:42:55 Details abc123
98092 Nonsensical Jr. 18 August 2018, 09:55:21 Details 55555
98093 Nonsensical Jr. 18 August 2018, 13:23:22 Details 454tdfddfhfghhf

Now, there are commit messages. The only problem is, they're not in English. Or any other language you might know. Hell, they're not even in binary! This normally happens when commit messages are mandated at configuration level. The developer can't commit unless he writes a commit remark... any remark. So to fulfill these requirements, they type some random keyboard sequence and click Save. Good for them... though this is probably worse than no message. Having no message is neutral. This is open contempt.

3. The Vague

Nothing solid.

Changeset By Time Remarks
113342667 Mr Vague 15 January 2018, 10:12:22 Details fixbug
113342668 Mr Vague 15 January 2018, 11:10:55 Details fixed bugs
113342669 Mr Vague 15 January 2018, 12:21:40 Details fixes

These irritate me the hardest. This is not some random sequence - it's actually readable (kind of) English. The only problem is, they say absolutely nothing. What in the loving heck is "fixbug", or any of the other permutations? Is the Mr Vague trying to say he fixed a bug? Exactly which bug? Did this provide any useful information, or at least more useful information than if he had not even bothered to leave remarks? Technically, yes. But only marginally. This basically screams, I have nothing useful to say, but I wanna say something just for the sake of saying something.

4. The Redundant

Really damn extra.

Changeset By Time Remarks
5566732 Mdm Redundant 9 March 2018, 23:21:09 Details 45178
5566733 Mdm Redundant 10 March 2018, 09:09:55 Details 45222
5566734 Mdm Redundant 10 March 2018, 11:58:29 Details 45232
5566734 Mdm Redundant 11 March 2018, 11:18:11 Details Mdm Redundant
5566734 Mdm Redundant 12 March 2018, 16:09:03 Details Mdm Redundant

These comments aren't random numbers. No, they're the ticket IDs for which the changesets are intended to fulfill. Are these useful? They might be... if not for the fact that these details are available anyway if you click on the Details link. So they save you a click... at the expense of more pertinent information. Better than no comments? Maybe. But not by much. (OK, I'm being kind. They're still utterly useless.) And in the last two commits, Mdm Redundant went one better... she simply left her name. Genius.

5. The Accusatory

It's all your fault!

Changeset By Time Remarks
103998 Sir Accusatory 30 May 2018, 12:18:49 Details The foreign id was not configured correctly. In my opinion, this would have been avoided if we had gone with denormalization of specific structures, as I recommended, instead of relying on foreign keys for verification of everything.

The first sentence was somewhat useful. The rest of it was smug, petulant and totally unnecessary. Even just "recommend denormalization of specific structures" would be preferred. This is at least neutral. Remember, when you piss people off with your remarks, half of your message is lost. This message started out as something useful. Unfortunately it got lost by the fact that the Sir Accusatory wasn't trying to be helpful, and was just trying to throw shade at the other developers.  Very unprofessional. Don't do this!

Are these commit remarks really all that useless?

Well, nothing's completely useless. If the company needed to assess the competency of their staff, this would be one of the easiest and obvious metrics. Seriously, you don't need to be a programming genius to know that these commit remarks are crap. It's more a matter of common sense.

Commit remarks are supposed to help, not hinder. When they say "soft skills are important", they don't mean software skills (though those are still important!), but rather, communication. If you are going to work in a team, you need to make your work easy to follow.

fixbug,
T___T

Tuesday, 28 August 2018

A look at User Authentication Factors (Part 2/2)

An authentication system is made out of authentication factors. There may be multiple factors, but whether a system is Single-factor Authentication, Two-factor Authentication (2FA) or Three-factor Authentication (3FA), depends on the number of different authentication factor types. For example, a simple Login screen is Single-factor authentication, even though the user has to key in both a login id and a password.

Instagram login screen.
Why? There are two authentication factors. But both of them are the same authentication type - Knowledge. That means there is only one authentication factor type in play. Even if you had to key in five passwords to be allowed entry, that would still be Single-factor Authentication.

Examples of Single-factor Authentication

As previously stated, a typical login screen is Single-factor Authentication. So is any type of system that only uses one authentication factor type.

ActiveSG gantry.
Like the gantries in ActiveSG swimming complexes. You scan your NRIC (a Possession authentication factor type), and it opens up.

Unlocking your mobile phone can be done via thumbprint scan (Inherence), facial recognition (Inherence) or a PIN (Knowledge). That's Single-factor Authentication.

Examples of Two-factor Authentication (2FA)

As mentioned previously, using your SingPass is 2FA. You key in your login id and password (Knowledge), then the systems sends an OTP to your mobile phone (Possession) for you to continue the login process.

Automatic Teller Machine.
Using an Automated Teller Machine (ATM) requires you to have your ATM card (Possession) and your PIN number (Knowledge).

The gantries in Changi Airport (all terminals) are 2FA. First, you scan your passport (Possession) and then your thumbprint (Inherence).

Examples of Three-factor Authentication (3FA)

There are virtually no examples of 3FA on websites. Biometrics are all but impossible right now on browsers. (CAPTCHA doesn't count because while it does - kind of - verify that you're not a bot, it can't verify that you're you.) Therefore, we're limited to only two authentication factor types - Knowledge and Possession.

Hi-tech security.

However, advanced security systems might require an electronic pass, a biometric scan and a passcode. That would qualify as 3FA.

That's all...

I just really wanted to explain 2FA. This might be a little more information than required. Hope this was interesting enough!

Thanks for tuning in! I had a scan-dalously good time.
T___T

Saturday, 25 August 2018

A look at User Authentication Factors (Part 1/2)

In 2016, Singapore introduced 2FA to SingPass authentication. It's been two years, and to my mortification most of the people I've met - techs included, oh my God - don't actually know what the term means beyond having to take an extra step (keying in a One-time Password, otherwise known as OTP) while logging in.

So yes, today we will take a look at what 2FA means in security. It's shorthand for "Two-factor Authentication".

Authentication Factors

During authentication, we make use of authentication factors. This could be just a password, or a thumbprint, or a codephrase. Something for the system to identify you by before allowing entry.

There are generally three types of authentication factors - Knowledge, Possession and Inherence.

Knowledge

This factor type is about what you know. It's something you memorize. In its most common form, it's a password, or a PIN number. If you've watched Mission Impossible: Fallout recently, there's this sequence where Tom Cruise's character, Ethan Hunt, supplies a phrase to a fellow agent.

"I am the storm."


Agent: Fate whispers to the warrior.
Ethan Hunt: There's a storm coming.
Agent: And the warrior whispers back...
Ethan Hunt: I am the storm.


"There's a storm coming." and "I am the storm." are the passphrases and those serve as useful examples of Knowledge authentication factor types.

Possession

Possession isn't about exorcism in this context (heh heh) but it's something you have. Something you keep on your person such as a mobile phone or a security token. Using it, the system can send a one-time password which the user can then use for authentication.

A typical RSA token.

Other examples of a Possession authentication factor type are - ATM card, NRIC card and credit card. Again, things you keep on your person.

Inherence

Don't be intimidated by this term - it basically means what you are. Things that are part of you, that we use in authentication. Like thumbprints, retina scans, facial recognition, voice recognition and so on. Biometrics.

Eye scan.

There's even something that scans the inner lining of your ear. It sounds weird as heck, but we live in strange times. Hey, if it works...

Next

Now that we've covered what the different authentication factor types are, let's take a look at how they make up an authentication system!

Friday, 17 August 2018

Spot The Bug: X marks the spot!

Good evening, and we're back for some Spot The Bug madness.

No bugs are safe!


I've got somber news. Jim "The Anvil" Neidhart, Canadian professional wrestler, just passed away on the 13th of this month and with him, a generous chunk of my childhood. I used to spend weekends glued to the TV gleefully watching the big man slam his opponents to the canvas and execute moves a man his size had no right to be making. (Ever seen a 280 pound standing dropkick? Looks as painful as it sounds.) I'd listen entranced at the mad cackles and the trademark snarls during his interviews. And I would go absolutely apeshit when he hit The Anvil Flattener.

Looted from wwe.com

It was reported that he fell and hit his head at home, then passed away at the age of 63. Guess Jim Deidhart, eh? (OK, ouch, that pun was lame even by my standards...)

Anyway. I'm getting all nostalgic just talking about it. So I was hacking together this little page which would feature a list of my favorite YouTube videos featuring Jim Neidhart. And there'd be a screen that would show the video I clicked on. I copied and pasted some old jQuery that would render a table off a JSON object containing all the data; namely, the title and links of the YouTube videos.

Here's the code. I made the JSON object smaller for brevity.
<!DOCTYPE html>
<html>
    <head>
        <title>The Pink and Black Attack!</title>
        <style>
            body
            {
                background-color: #DD8888;
            }

            #tblMain tr td b
            {
                color: #000000;
            }

            #tblMain tr td b
            {
                color: #FFDDDD;
            }

            button
            {
                background-color: #FFDDDD;
                color: #DD8888;
                font-weight: bold;
            }

            div
            {
                width: 300px;
                float: left;
            }
        </style>

        <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>

        <script>
        $(document).ready(function (x)
        {
            var pbdata =
            [
                {"desc":"Anvil vs Bad News Brown", "link":"7nhMnYjIFYk"},
                {"desc":"Anvil challenges Bulldog", "link":"W3WYWiqkL3M"},
                {"desc":"Classic Promo", "link":"glFtNFtpEPk"},
                {"desc":"Anvil vs Mr Perfect", "link":"0llHaAsPeeE"},
                {"desc":"Anvil shoot interview", "link":"VAoLzHf1UUY"},
                {"desc":"Anvil promo for Bad News Brown", "link":"yeEF-TAmE6c"},
                {"desc":"Hart Foundation promo", "link":"srSJUctZHf4"},
                {"desc":"Hart Foundation Tag Champs", "link":"GRy-w1qjW2g"},
            ];

            var tr;
            var td;
            var btn;

            pbdata.forEach
            (
                function(x)
                {
                    tr = $("<tr></tr>");

                    td = $("<td></td>");
                    td.html(x.desc);   
                    tr.append(td);

                    btn = $("<button>Go</button>");
                    btn.click(function(x)
                    {
                        $("#ifmPlay").attr("src", "http://www.youtube.com/embed/" + x.link);
                    }
                    );

                    td = $("<td></td>");
                    td.append(btn);

                    tr.append(td);

                    $("#tblMain").append(tr);
                }
            )           
        });

        </script>
    </head>
    <body>
        <div>
            <table id="tblMain">
                <tr>
                    <td><b>Description</b></td>
                    <td><b>Link</b></td>
                </tr>
            </table>
        </div>
        <div>
            <iframe id="ifmPlay" width="420" height="315" src="">
            </iframe>
        </div>   
    </body>
</html>


What went wrong

The table rendered just fine. Pink and black, nice huh? Problem was, no video would play when I clicked the buttons.

Why it went wrong

See this? That's what I did to make the button play the video. That was the problem.
btn.click(function(x)
{
    $("#ifmPlay").attr("src", "http://www.youtube.com/embed/" + x.link);
}


I'm really, really used to making callbacks like this...
function(x)
{

}


...so much so I totally forgot this was already within a callback of its own, also using x as the name of the parameter! So x, in this new scope, was referencing the event of the mouseclick instead of the current element in the pbdata object!

                function(x)
                {
                    tr = $("<tr></tr>");

                    td = $("<td></td>");
                    td.html(x.desc);   
                    tr.append(td);

                    btn = $("<button>Go</button>");
                    btn.click(function(x)
                    {
                        $("#ifmPlay").attr("src", "http://www.youtube.com/embed/" + x.link);
                    }
                    );

                    td = $("<td></td>");
                    td.append(btn);

                    tr.append(td);

                    $("#tblMain").append(tr);
                }


So instead of the URL being "http://www.youtube.com/embed/7nhMnYjIFYk" for example, it would only be "http://www.youtube.com/embed/", which would still get to YouTube, but return absolutely nothing but a blank screen. And there would be no error message in the console because x was still a valid object.

How I fixed it

This one was straightforward. Merely use a different parameter name.
btn.click(function(y)
{
    $("#ifmPlay").attr("src", "http://www.youtube.com/embed/" + x.link);
}


And all's right with the world!

Conclusion

Getting caught mixing up your scopes is a fairly common problem in jQuery, or even just JavaScript. Luckily, this took me all of five minutes to solve. But this can be a right headscratcher if you see no error messages and the problem looks like the videos themselves.

x-quisitely yours,
T___T